Improve the error reporting in HTTP client sample

This commit is contained in:
Bill Avery 2023-05-10 12:55:32 -07:00
Родитель 31b3312b2d
Коммит 81a3854c2a
6 изменённых файлов: 84 добавлений и 14 удалений

Просмотреть файл

@ -51,7 +51,7 @@ public:
explicit Query(std::string_view host, std::string_view port, std::string_view target,
int version) noexcept;
std::future<std::string> getRelay(std::string&& queryArg,
std::future<std::optional<std::string>> getRelay(std::string&& queryArg,
std::optional<std::string>&& operationNameArg,
std::optional<std::string>&& variablesArg) const;
@ -73,7 +73,7 @@ Query::Query(
// Based on:
// https://www.boost.org/doc/libs/1_82_0/libs/beast/example/http/client/awaitable/http_client_awaitable.cpp
std::future<std::string> Query::getRelay(std::string&& queryArg,
std::future<std::optional<std::string>> Query::getRelay(std::string&& queryArg,
std::optional<std::string>&& operationNameArg, std::optional<std::string>&& variablesArg) const
{
response::Value payload { response::Type::Map };
@ -99,7 +99,7 @@ std::future<std::string> Query::getRelay(std::string&& queryArg,
const char* port,
const char* target,
int version,
std::string requestBody) -> net::awaitable<std::string> {
std::string requestBody) -> net::awaitable<std::optional<std::string>> {
// These objects perform our I/O. They use an executor with a default completion token
// of use_awaitable. This makes our code easy, but will use exceptions as the default
// error handling, i.e. if the connection drops, we might see an exception.
@ -150,7 +150,7 @@ std::future<std::string> Query::getRelay(std::string&& queryArg,
throw boost::system::system_error(ec, "shutdown");
}
co_return std::string { std::move(res.body()) };
co_return std::make_optional<std::string>(std::move(res.body()));
}(m_host.c_str(), m_port.c_str(), m_target.c_str(), m_version, std::move(requestBody)),
net::use_future);
@ -182,8 +182,78 @@ int main(int argc, char** argv)
auto serviceResponse = client::parseServiceResponse(
service->resolve({ query, GetOperationName(), std::move(variables), launch }).get());
auto result = client::query::relayQuery::parseResponse(std::move(serviceResponse.data));
auto errors = std::move(serviceResponse.errors);
std::cout << result.relay << std::endl;
if (result.relay)
{
std::cout << *result.relay << std::endl;
}
if (!errors.empty())
{
std::cerr << "Errors executing query:" << std::endl << GetRequestText() << std::endl;
for (const auto& error : errors)
{
std::cerr << "Error: " << error.message;
if (!error.locations.empty())
{
bool firstLocation = true;
std::cerr << ", Locations: [";
for (const auto& location : error.locations)
{
if (!firstLocation)
{
std::cerr << ", ";
}
firstLocation = false;
std::cerr << "(line: " << location.line << ", column: " << location.column
<< ")";
}
std::cerr << "]";
}
if (!error.path.empty())
{
bool firstSegment = true;
std::cerr << ", Path: ";
for (const auto& segment : error.path)
{
std::visit(
[firstSegment](const auto& value) noexcept {
using _Type = std::decay_t<decltype(value)>;
if constexpr (std::is_same_v<std::string, _Type>)
{
if (!firstSegment)
{
std::cerr << "/";
}
std::cerr << value;
}
else if constexpr (std::is_same_v<int, _Type>)
{
std::cerr << "[" << value << "]";
}
},
segment);
firstSegment = false;
}
}
std::cerr << std::endl;
}
}
}
catch (const std::runtime_error& ex)
{

Просмотреть файл

@ -83,7 +83,7 @@ Response parseResponse(response::Value&& response)
{
if (member.first == R"js(relay)js"sv)
{
result.relay = ModifiedResponse<std::string>::parse(std::move(member.second));
result.relay = ModifiedResponse<std::string>::parse<TypeModifier::Nullable>(std::move(member.second));
continue;
}
}

Просмотреть файл

@ -64,7 +64,7 @@ struct [[nodiscard]] Variables
struct [[nodiscard]] Response
{
std::string relay {};
std::optional<std::string> relay {};
};
[[nodiscard]] Response parseResponse(response::Value&& response);

Просмотреть файл

@ -65,7 +65,7 @@ service::AwaitableResolver Query::resolveRelay(service::ResolverParams&& params)
auto result = _pimpl->getRelay(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argQuery), std::move(argOperationName), std::move(argVariables));
resolverLock.unlock();
return service::ModifiedResult<std::string>::convert(std::move(result), std::move(params));
return service::ModifiedResult<std::string>::convert<service::TypeModifier::Nullable>(std::move(result), std::move(params));
}
service::AwaitableResolver Query::resolve_typename(service::ResolverParams&& params) const
@ -92,7 +92,7 @@ service::AwaitableResolver Query::resolve_type(service::ResolverParams&& params)
void AddQueryDetails(const std::shared_ptr<schema::ObjectType>& typeQuery, const std::shared_ptr<schema::Schema>& schema)
{
typeQuery->AddFields({
schema::Field::Make(R"gql(relay)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), {
schema::Field::Make(R"gql(relay)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv), {
schema::InputValue::Make(R"gql(query)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv),
schema::InputValue::Make(R"gql(operationName)gql"sv, R"md()md"sv, schema->LookupType(R"gql(String)gql"sv), R"gql()gql"sv),
schema::InputValue::Make(R"gql(variables)gql"sv, R"md()md"sv, schema->LookupType(R"gql(String)gql"sv), R"gql()gql"sv)

Просмотреть файл

@ -16,13 +16,13 @@ namespace methods::QueryHas {
template <class TImpl>
concept getRelayWithParams = requires (TImpl impl, service::FieldParams params, std::string queryArg, std::optional<std::string> operationNameArg, std::optional<std::string> variablesArg)
{
{ service::AwaitableScalar<std::string> { impl.getRelay(std::move(params), std::move(queryArg), std::move(operationNameArg), std::move(variablesArg)) } };
{ service::AwaitableScalar<std::optional<std::string>> { impl.getRelay(std::move(params), std::move(queryArg), std::move(operationNameArg), std::move(variablesArg)) } };
};
template <class TImpl>
concept getRelay = requires (TImpl impl, std::string queryArg, std::optional<std::string> operationNameArg, std::optional<std::string> variablesArg)
{
{ service::AwaitableScalar<std::string> { impl.getRelay(std::move(queryArg), std::move(operationNameArg), std::move(variablesArg)) } };
{ service::AwaitableScalar<std::optional<std::string>> { impl.getRelay(std::move(queryArg), std::move(operationNameArg), std::move(variablesArg)) } };
};
template <class TImpl>
@ -58,7 +58,7 @@ private:
virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0;
virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0;
[[nodiscard]] virtual service::AwaitableScalar<std::string> getRelay(service::FieldParams&& params, std::string&& queryArg, std::optional<std::string>&& operationNameArg, std::optional<std::string>&& variablesArg) const = 0;
[[nodiscard]] virtual service::AwaitableScalar<std::optional<std::string>> getRelay(service::FieldParams&& params, std::string&& queryArg, std::optional<std::string>&& operationNameArg, std::optional<std::string>&& variablesArg) const = 0;
};
template <class T>
@ -70,7 +70,7 @@ private:
{
}
[[nodiscard]] service::AwaitableScalar<std::string> getRelay(service::FieldParams&& params, std::string&& queryArg, std::optional<std::string>&& operationNameArg, std::optional<std::string>&& variablesArg) const final
[[nodiscard]] service::AwaitableScalar<std::optional<std::string>> getRelay(service::FieldParams&& params, std::string&& queryArg, std::optional<std::string>&& operationNameArg, std::optional<std::string>&& variablesArg) const final
{
if constexpr (methods::QueryHas::getRelayWithParams<T>)
{

Просмотреть файл

@ -2,5 +2,5 @@
# Licensed under the MIT License.
type Query {
relay(query: String!, operationName: String, variables: String): String!
relay(query: String!, operationName: String, variables: String): String
}