IGraphQLClientRequest
An outbound GraphQL request whose result is read as TResponse. Implement it directly with a literal query, derive from GraphQLResourceRequest to load the query from an embedded .graphql file, or derive from TypedRequest<TResponse> (in Trax.Api.GraphQL.Client.Typed) to generate it from the response type. Run it with IGraphQLClientExecutor.Run.
Definition
public interface IGenericGraphQLClientRequest
{
string Query { get; }
object? Variables => null;
}
public interface IGraphQLClientRequest<out TResponse> : IGenericGraphQLClientRequest
{
JsonElement UnwrapDataElement(JsonElement data); // default implementation
TResponse Extract(JsonElement data, JsonSerializerOptions options); // default implementation
bool UsesDefaultExtractor => true;
}Only Query must be implemented. Everything else has a default.
| Member | Default | Description |
|---|---|---|
Query | (required) | The GraphQL document. It must hold exactly one operation, before or after any fragments: requests are sent without an operation name, so a second operation is refused at validation. Keep it constant and pass values through Variables, because validation is cached per query text |
Variables | null | The operation's variables, serialized as the variables object. An anonymous object or a dictionary both work |
UnwrapDataElement(data) | When data has exactly one top-level property, returns its value; otherwise returns data unchanged | Navigates from the data envelope to the element that is deserialized. Override it to walk a nested envelope |
Extract(data, options) | Calls UnwrapDataElement, returns default for a JSON null, and otherwise deserializes with the client's JSON options | Override it to reshape the response yourself |
UsesDefaultExtractor | true | Set to false when you override Extract. Response-shape checking (ResponseStrictness) runs only when this is true, since a custom extractor may reshape the response in ways the check cannot model |
IGenericGraphQLClientRequest is the non-generic view used to scan and validate requests without knowing their response type. Implement IGraphQLClientRequest<TResponse>, not it.
Example
public sealed class GetPlayerRequest : IGraphQLClientRequest<PlayerProfile>
{
public required string Id { get; init; }
public string Query => """
query GetPlayer($id: String!) {
player(id: $id) { id name level }
}
""";
public object? Variables => new { id = Id };
}
public sealed record PlayerProfile(string Id, string Name, int Level);The response { "data": { "player": { ... } } } has one top-level field, so the default UnwrapDataElement descends into player and deserializes it as PlayerProfile.
IGraphQLClientExecutor
public interface IGraphQLClientExecutor
{
Task<TReturn> Run<TReturn>(
IGraphQLClientRequest<TReturn> request,
CancellationToken cancellationToken = default);
}Registered as a singleton by AddTraxGraphQLClient (keyed, by AddKeyedTraxGraphQLClient) and safe to use concurrently. Run:
- Validates
Queryagainst the client's schema. The first validation of a query text loads the schema if needed; later ones hit the cache. - Sends it as a query or a mutation, according to the operation.
- Throws if the server returned errors or no data.
- Checks the response shape when the client's strictness is not
Lenientand the request uses the default extractor. - Returns
Extract(data, options).
| Exception | When |
|---|---|
GraphQLValidationException | The query does not validate, has no operation, or has more than one. Nothing is sent. Query and Errors say why |
GraphQLSchemaIntrospectionException | The schema could not be loaded for validation |
GraphQLExecutionException | The server returned GraphQL errors (in Errors), the response had no data, or deserializing it as TReturn produced null (Errors is empty) |
JsonException | The default extractor could not read the data as TReturn, for example a string where the type has a number. It is not wrapped |
GraphQLResponseShapeException | The response shape differs from TReturn under ThrowOnDrift |
NotSupportedException | The operation is a subscription |
Transport failures (a refused connection, a timeout, a non-success status the transport reports) surface as the exceptions GraphQL.Client and HttpClient throw.
GraphQLClientAttribute
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class GraphQLClientAttribute(object key) : AttributeNames the keyed client a request belongs to. It decides which client's validation checks the request (see AddKeyedTraxGraphQLClient); it does not decide where the request is sent.
Package
dotnet add package Trax.Api.GraphQL.Client