Skip to main content

GraphQL

GraphQL is the primary means of querying your typegraph. This page documents all the semantics of how your typegraph translates into a GraphQL schema.

Query and Mutation

The root functions passed to the expose function will be added as fields to the special query and mutation GraphQL objects. Under which object a function is assigned depends on it's effect. Note that this assignment still holds for deeply nested functions so be sure to avoid including functions that have mutating effects under query responses or vice versa.

Variables

While GraphQL Variables work as expected for the most part, the typegate currently does not do type validation of variables for the provided query documents.

query ($varRight: String!, $varWrong: Int!) {
foo1: foo(in: $varRight)
foo2: foo(in: $varWrong)
}
{
"varRight": "string",
# request will work as long as varWrong is string
# even if variable above was annotated as Int
"varWrong": "AlsoString",
}

Types

Scalars

The simple primitive typegraph types translate directly to their GraphQL equivalent. This includes standard scalar variants like t.uuid or any user declared aliases with custom configurations. No custom GraphQL scalars are generated for such types.

TypeGraphQL typeDescription
t.integer()IntRepresents signed 32-bit integers.
t.float()FloatRepresents signed double-precision values as specified by IEEE 754.
t.boolean()BooleanRepresents true or false.
t.string()StringRepresents textual data as UTF-8 character sequences.

Files

File types, primarily used through the S3Runtime, translate to a custom scalar called File in the GraphQL schema. The S3Runtime provides a set of helpers for all your file needs including support for multipart HTTP requests for file upload.

Structs

t.structs types translate to:

Lists

t.list types simply convert to GraphQL list types.

Functions

t.func types are represented by their output type in the GraphQL schema. If their input struct has fields present, these are converted to arguments for the field.

Unions and Eithers

Unions and either translate to a number of different forms depending on their usage in the graph and their composition.

When used as a field in an input struct, unions/eithers are converted to custom scalars since the GraphQL spec doesn't allow GraphQL unions on input types. These scalars expect the standard JSON representation of your value and that is all.

When querying union/either values, there are a few more details. For struct variants, the standard GraphQL rules apply and inline fragments must be used. Currently, all struct variants must have inline fragments present even if the user is not interested in them. And as per GraphQL spec, common field querying is not supported and any fields must be part of the inline fragment. Unlike the GraphQL spec, this includes the __typename field which must be included in the fragments instead.

# introspection schema
union MyUnion = Struct1 | Struct2

type Struct1 {
foo: String!
bar: String!
}

type Struct2 {
foo: String!
baz: String!
}

# introspection expected query (THIS IS WRONG)
query {
myUnion {
# common fields are not supported
__typename
foo
... on Struct1 {
bar
}
... on Struct2 {
baz
}
}
}

# actual expected query (THIS IS RIGHT)
query {
myUnion {
... on Struct1 {
# common fields must be included each time
__typename
foo
bar
}
... on Struct2 {
__typename
foo
baz
}
}
}

For scalar variant, the introspected GraphQL schema will include a _NameOfScalar variant in the introspection schema but the value is returned at the field level as a simple scalar. That is, GraphQL API explorers will show union object members that include the scalar values and they'll prompt you to use inline fragments for querying the scalar members. But the typegate will reject these kind of queries in preference to simple fields. Look at the following example:

# introspection schema
union MyUnion = _String | _Integer

type _String {
string: String!
}

type _Integer {
integer: Int!
}

# introspection expected query (THIS IS WRONG)
query {
myUnion {
... on _String {
string
}
... on _Integer {
integer
}
}
}

# actual expected query (THIS IS RIGHT)
query {
# no subfield selection at all required
# since all members are scalars
myUnion
}

# received json
{
"myUnion": "string"
}

List members act accordingly to their wrapped times. Lists of scalars are treated as scalars and lists of composites as a standard GraphQL composites list.

The following playground shows all the different types of unions/eithers:

Loading...