Public
Documentation for GraphQLClient's public interface.
Client
GraphQLClient.Client
— TypeClient(endpoint; headers=Dict(), introspect=true)
Client(endpoint, ws_endpoint; headers=Dict(), introspect=true)
GraphQL client. If just endpoint
is provided, ws_endpoint
is assumed to be the same as endpoint with "http" replaced by "ws".
By default, introspection will be performed on the client. This can be turned off by setting the introspect
keyword argument to false
.
Fields - Public Interface
endpoint::String
: endpoint for queries and mutations.ws_endpoint::String
: endpoint for subscriptions.headers::Dict
: contains client specific headers.introspection_complete::Bool
: set totrue
once introspection has been performed.queries::Vector{String}
: list of available queries.mutations::Vector{String}
: list of available mutations.subscriptions::Vector{String}
: list of available subscriptions.
Fields - Internal Use
type_to_fields_map::Dict{String, Dict{String, Dict{String, Any}}}
: maps GQL types to their fields.query_to_type_map::Dict{String, String}
: maps GQL queries, mutations and subscriptions to the type(s) of their outputs(s).query_to_args_map::Dict{String, Dict{String, String}}
: maps GQL queries, mutations and subscriptions to their arguments and types.input_object_fields_to_type_map::Dict{String, Dict{String, String}}
: maps GQL input objects to their fields/types.schema::Dict{String, Any}
: full schema of server.introspected_types::Dict{String, DataType}
: dictionary containing all introspected types.
Examples
julia> client = Client("https://countries.trevorblades.com")
GraphQLClient Client
endpoint: https://countries.trevorblades.com
ws_endpoint: wss://countries.trevorblades.com
julia> client = Client("https://countries.trevorblades.com", "wss://countries.trevorblades.com")
GraphQLClient Client
endpoint: https://countries.trevorblades.com
ws_endpoint: wss://countries.trevorblades.com
GraphQLClient.global_graphql_client
— Functionglobal_graphql_client()
Retrieve the global Client
.
global_graphql_client(client::Client)
Set the global Client.
GraphQLClient.full_introspection!
— Functionfull_introspection!(client::Client)
Performs a full instrospection of the GraphQL schema of the client
. The results are stored in the client struct.
See also: Client
GraphQLClient.get_queries
— Functionget_queries(client::Client)
Returns all queries available from GraphQL server. If introspection has not been performed, will run full_introspection!(client)
.
GraphQLClient.get_mutations
— Functionget_mutations(client::Client)
Returns all mutations available from GraphQL server. If introspection has not been performed, will run full_introspection!(client)
.
GraphQLClient.get_subscriptions
— Functionget_subscriptions(client::Client)
Returns all subscriptions available from GraphQL server. If introspection has not been performed, will run full_introspection!(client)
.
Operations
GraphQLClient.query
— Functionquery([client::Client], query_name::Union{Alias, AbstractString}, output_type::Type=Any; kwargs...)
Perform a query on the server, using the global client if client
not supplied.
If no output_fields
are supplied, all possible fields (determined by introspection of client
) are returned.
The query uses the endpoint
field of the client
.
By default query
returns a GQLReponse{Any}
, where the data for an individual query can be found by gql_response.data[query_name]
.
Arguments
client::Client
: GraphQL client (optional). If not supplied,global_graphql_client
is used.query_name::Union{Alias, AbstractString}
: name of query in server.output_type::Type=Any
: output data type for query response object. An object of typeGQLResponse{output_type}
will be returned. For further information, see documentation forGQLResponse
.
Keyword Arguments
query_args=Dict()
: dictionary of query argument key value pairs - can be nested with dictionaries and vectors.output_fields=String[]
: output fields to be returned. Can be a string, or composed of dictionaries and vectors. If empty,query
will attempt to return all fields.direct_write=false
: iftrue
, the query is formed by generating a string fromquery_args
directly, and the introspected schema is not used. Any ENUMs must be wrapped in aGQLEnum
. Seedirectly_write_query_args
for more information.retries=1
: number of times the mutation will be attempted before erroring.readtimeout=0
: HTTP request timeout length. Set to 0 for no timeout.throw_on_execution_error=false
: set totrue
to throw an exception if the GraphQL server response contains errors that occurred during execution.verbose=0
: set to 1, 2 for extra logging.
See also: GQLResponse
GraphQLClient.mutate
— Functionmutate([client::Client], mutation_name::Union{Alias, AbstractString}, args::AbstractDict, output_type::Type=Any; kwargs...)
Perform a mutation on the server, using the global client if client
not supplied.
If no output_fields
are supplied, none are returned.
By default mutate
returns a GQLReponse{Any}
, where the data for an individual mutation can be found by gql_response.data[mutation_name]
.
The mutation uses the endpoint
field of the client
.
Arguments
client::Client
: GraphQL client (optional). If not supplied,global_graphql_client
is used.mutation_name::Union{Alias, AbstractString}
: name of mutation_name.args
: dictionary of mutation argument key value pairs - can be nested with dictionaries and vectors.output_type::Type=Any
: output data type for query response object. An object of typeGQLResponse{output_type}
will be returned.For further information, see documentation forGQLResponse
.
Keyword Arguments
output_fields=String[]
: output fields to be returned. Can be a string, or composed of dictionaries and vectors.direct_write=false
: iftrue
, the query is formed by generating a string fromargs
directly, and the introspected schema is not used. Any ENUMs must be wrapped in aGQLEnum
. Seedirectly_write_query_args
for more information.retries=1
: number of times the mutation will be attempted before erroring.readtimeout=0
: HTTP request timeout length. Set to 0 for no timeout.throw_on_execution_error=false
: set totrue
to throw an exception if the GraphQL server response contains errors that occurred during execution.
See also: GQLResponse
GraphQLClient.open_subscription
— Functionopen_subscription(fn::Function,
[client::Client],
subscription_name::Union{Alias, AbstractString},
output_type::Type=Any;
sub_args=Dict(),
output_fields=String[],
initfn=nothing,
retry=true,
subtimeout=0,
stopfn=nothing,
throw_on_execution_error=false)
Subscribe to subscription_name
, running fn
on each received result and ending the subcription when fn
returns true
.
By default fn
receives a GQLReponse{Any}
, where the data for an individual result object can be found by gql_response.data[subscription_name]
.
If used, initfn
is called once the subscription is open.
The subscription uses the ws_endpoint
field of the client.
This function is designed to be used with the do
keyword.
Arguments
fn::Function
: function to be run on each result, recieves the response from the subscription. Must return a boolean to indicate whether or not to close the subscription, with
true` closing the subscription.client::Client
: GraphQL client (optional). If not supplied,global_graphql_client
is used.subscription_name::Union{Alias, AbstractString}
: name of subscription in server.output_type::Type=Any
: output data type for subscription response object. An object of typeGQLResponse{output_type}
will be returned.For further information, see documentation forGQLResponse
.
Keyword Arguments
sub_args=Dict()
: dictionary of subscription argument key value pairs - can be nested with dictionaries and vectors.output_fields=String[]
: output fields to be returned. Can be a string, or composed of dictionaries and vectors.initfn=nothing
: optional function to be run once subscription is itialised.retry=true
: retry if subscription fails to open.subtimeout=0
: ifstopfn
supplied, this is the period that it is called at. Ifstopfn
is not supplied, this is the timeout for waiting for data. The timer is reset after every subscription result is received.stopfn=nothing
: a function to be called everysubtimeout
that stops the subscription if it returns positive. The timer is reset after every subscription result is received.throw_on_execution_error=false
: set totrue
to stop an error being thrown if the GraphQL server response contains errors that occurred during execution.verbose=0
: set to 1, 2 for extra logging.
Examples
julia> open_subscription("subSaveUser", sub_args=Dict("role" => "SYSTEM_ADMIN")) do result
fn(result)
end
See also: GQLResponse
GraphQLClient.execute
— Functionexecute([client::Client], query::AbstractString, output_type::Type{T}=Any; kwargs...) where T
execute([client::Client], payload::AbstractDict, output_type::Type{T}=Any; kwargs...) where T
execute(endpoint::AbstractString, query::AbstractString, headers::AbstractDict=Dict(), output_type::Type{T}=Any; variables=Dict(), kwargs...) where T
execute(endpoint::AbstractString, payload::AbstractDict, headers::AbstractDict=Dict(), output_type::Type{T}=Any; kwargs...) where T
Executes a HTTP Post request and returns the result as a GQLResponse{T}
.
This function allows for lower level querying of the GraphQL server. A Client
, the global client or endpoint can be queried with a query string (and optionally variables can be supplied to the keyword argument), or with the payload directly. This payload is typically a dictionary containing the key "query" at a minimum, with variables
(and other keys) begin optional.
For all methods, the content type is set to application/json
unless this is set differently in client.headers.
/headers
.
Keyword Arguments
variables=Dict()
: dictionary of variable name to value, used to construct the payload.retries=1
: number of times to retry.readtimeout=0
: close the connection if no data is received for this many seconds. Usereadtimeout = 0
to disable.operation_name=""
: name of operation to execute. Must be supplied if more than one operation in query. EmptyString
is equal to no name supplied.throw_on_execution_error=false
: set totrue
to throw an exception if the GraphQL server response contains errors that occurred during execution. Otherwise, errors can be found in the error field of the return value.
See also: Client
, GQLResponse
Examples
julia> client = Client("https://countries.trevorblades.com");
julia> GraphQLClient.execute(client, "query{country(code:\"BR\"){name}}")
GraphQLClient.GQLResponse{Any}
data: Dict{String, Any}
country: Dict{String, Any}
julia> global_graphql_client(Client("https://countries.trevorblades.com"));
julia> GraphQLClient.execute("query{country(code:\"BR\"){name}}")
GraphQLClient.GQLResponse{Any}
data: Dict{String, Any}
country: Dict{String, Any}
julia> GraphQLClient.execute("https://countries.trevorblades.com", "query{country(code:\"BR\"){name}}")
GraphQLClient.GQLResponse{Any}
data: Dict{String, Any}
country: Dict{String, Any}
julia> GraphQLClient.execute(
"https://countries.trevorblades.com",
Dict("query" => "query{country(code:\"BR\"){name}}")
)
GraphQLClient.GQLResponse{Any}
data: Dict{String, Any}
country: Dict{String, Any}
julia> query_string = """
query getCountries{countries{name}}
query getLanguages{languages{name}}
"""
julia> GraphQLClient.execute(client, query_string, operation_name="getCountries")
GraphQLClient.GQLResponse
— TypeGQLResponse{T}
Output format for GraphQL queries, mutations and subscriptions.
Accessing data
The data
field of a GQLResponse
object is a Union{Nothing, Dict{String, Union{Nothing, T}}}
, where the key is the query, mutation or subscription name (or Alias
) and T
is specified in the output_type
argument of query
, mutate
, open_subscription
and execute
. If this argument is not supplied, it will default to Any
. Typically this results in combinations of dictionaries and vectors which can be accessed intuitively, following the GraphQL server schema. Alternatively, if execution of a particular query fails, the value for that query will be nothing
.
It is, however, possible to provide types with a StructTypes definition and GraphQLClient will attempt to build the object from the response. This must be done carefully, however, as if the response is not as expected (for example, missing fields or unexpected nulls) then the deserialisation of the response into the struct can fail. If this occurs it should be indicated by the warnings and errors outputted by GraphQLClient.
The fields of the type to deserialise can be modified to be a Union
of Nothing
and their original type, as the deserialisation will input Nothing
if the field is missing or null.
Comparison with GraphQL Response Specification
The GraphQL specification specifies that the response can contain data
, errors
and extensions
fields. It is important to note that in a GQLResponse
object, both data
and errors
fields will always be present, regardless of whether or not they are returned in the server response. This is to ensure queries can be type stable. If errors
is nothing
, then no errors occurred. If data
is null
this indicates an error occurred either during or before execution.
GraphQLClient.GQLEnum
— TypeGQLEnum
When using direct_write=true
in queries and mutations, ENUMs must be wrapped in this type to ensure that they are not wrapped in quotes in the query string.
See directly_write_query_args
for more information and examples.
GraphQLClient.Alias
— TypeAlias
Contains an alias for a GraphQL field or query. Alias
es can be used in the output_fields
keyword argument as well as directly instead of query, mutation and subscription names.
Examples
Using an Alias
instead of the query name:
julia> client = Client("https://countries.trevorblades.com");
julia> alias = Alias("country_alias", "country");
julia> query(client, alias, query_args=Dict("code"=>"BR"), output_fields=["name"]).data
Dict{String, Any} with 1 entry:
"country_alias" => Dict{String, Any}("name"=>"Brazil")
Using an Alias
in output_fields
:
julia> field_alias = Alias("country_name_alias", "name");
julia> query(client, "country", query_args=Dict("code"=>"BR"), output_fields=[field_alias]).data
Dict{String, Any} with 1 entry:
"country" => Dict{String, Any}("country_name_alias"=>"Brazil")
GraphQLClient.@gql_str
— Macro@gql_str(document, throw_on_error=true)
Create and optionally validate a GraphQL query string.
The string is parsed and semi-validated by GraphQLParser.jl. Validation that does not need the schema from the server is performed. For further information see the GraphQLParser documentation.
Parsing errors will always be thrown, but other validation errors can be turned off using the second argument.
An additional advantage of using this macro is that dollar signs do not need to be escaped (see example below).
Examples
General usage
julia> client = Client("https://countries.trevorblades.com");
julia> str = gql"""
query($code: ID!){
country(
code:$code
){
name
}
}
""";
julia> variables = Dict("code" => "BR");
julia> GraphQLClient.execute(client, str; variables=variables)
GraphQLClient.GQLResponse{Any}
data: Dict{String, Any}
country: Dict{String, Any}
Parsing error
julia> str = gql"""
query(code: ID!){ # no $ before variable name
country(
code:$code
){
name
}
}
""";
# ERROR: LoadError: ArgumentError: invalid GraphQL string at byte position 7 while parsing
# Variable name must start with '$'
# query(code: ID!){ # no $ before
# ^
Validation error
julia> str = gql"""
{
countries{
name
}
}
query{ # Can't have another operation when there is an anonymous operation
countries{
name
}
}
""";
# ERROR: LoadError: Validation Failed
# GraphQLParser.AnonymousOperationNotAlone
# message: This anonymous operation must be the only defined operation.
# location: Line 1 Column 1
Turning validation off
julia> str = @gql_str """
{
countries{
name
}
}
query{ # Can't have another operation when there is an anonymous operation
countries{
name
}
}
""" false
# No error
Type Introspection
GraphQLClient.introspect_object
— Functionintrospect_object([client::Client],
object_name;
force=false,
reset_all=false,
parent_type=nothing,
parent_map=Dict{String, Type}(),
mutable=true,
allowed_level=2,
custom_scalar_types=Dict{String, DataType}())
Introspects an object and creates a Julia type.
Due to the recursion that is possible with GraphQL schemas, this introspection can be difficult. Please read this docstring carefully.
Parent Type
All introspected type, by default, will be given the parent type AbstractIntrospectedStruct
. The parent type of the top level object being introspected can be set by parent_type
, and the parent types of any object being introspected can be set using the parent_map
dictionary. If object_type
is a key in parent_map
and parent_type
is not nothing
, the value of parent_type
will take precedence.
StructTypes
AbstractIntrospectedStruct
has a defined StructType
of Struct
for JSON serialisation. You can define StructType
s for the concrete type that is introspected by doing
StructTypes.StructType(::Type{GraphQLClient.get_introspected_object(object_name)}) = StructTypes.Struct()
Recursion
Recursion is handled by two methods:
- Providing the
allowed_level
kwarg to control how deep introspection goes. - Maintaining a list of objects that are currently being introspected. No object can be instrospected twice and a type cannot be used in a type definition until it has been defined itself. Therefore if this situation occurs, the fields that need to use the not-yet-defined type are ignored. This means the order in which objects are intropsected can have an impact on the final structs.
For example consider the following objects
Country:
- name: String
- leader: Person
Person:
- name: String
- countryOfBirth: Country
If we introspected Country
first, the Person
object would not contain the countryOfBirth
field, as it is impossible to set the type of that field to Country
before it is defined itself. If we introspected Person
first, the Country
boject would not contain the leader
field for the same reason.
Keyword Arguments
force=false
: iffalse
, the introspection will use already introspected types for objects if they exist. Iftrue
, any previously introspected types will be overwritten if they are introspected whilst introspectingobject_name
. Use with caution, as other types may rely on types that are then overwritten.reset_all
: delete all introspected types to start from a clean sheet.parent_type=nothing
: the parent type to give to the new introspected struct. See comment above.parent_map=Dict{String, Type}()
: dictionary to maps object names to desired parent types. Ifparent_type
is supplied, this value will take precedence over the entry inparent_map
forobject_name
.mutable=true
: boolean to set the mutability of top level and all lower level types.allowed_level=2
: how many levels of introspection are allowed. For example, if this is1
then only top level fields that are objects will be in the introspected type.custom_scalar_types
: dictionary of custom GraphQL scalar type to Julia type. This kwarg enables custom scalar types to be introspected to the correct type.
GraphQLClient.get_introspected_type
— Functionget_introspected_type([client::Client], object_name::String)
Return the introspected Type
for an object.
GraphQLClient.list_all_introspected_objects
— Functionlist_all_introspected_objects([client::Client])
Return a Vector
of the objects which have been introspected.
GraphQLClient.initialise_introspected_struct
— Functioninitialise_introspected_struct([client::Client], name::String)
initialise_introspected_struct([client::Client], name::SubString)
initialise_introspected_struct(T::Type)
Initialise an introspected struct with all fields set to nothing. If name of type supplied as string, this get the Type
from client.introspected_types
.
GraphQLClient.create_introspected_struct
— Functioncreate_introspected_struct([client::Client], object_name::AbstractString, fields::AbstractDict)
Creates a struct for the object specified and populates its fields with the keys and values of fields
.
Examples
julia> GraphQLClient.create_introspected_struct("ResultObject",Dict(:resultId=>"MyResult", :Score => 1.0))
ResultObject
Score : 1.0
resultId : MyResult
GraphQLClient.AbstractIntrospectedStruct
— TypeAbstractIntrospectedStruct
Default supertype for introspected structs.