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.
Type | GraphQL type | Description |
---|---|---|
t.integer() | Int | Represents signed 32-bit integers. |
t.float() | Float | Represents signed double-precision values as specified by IEEE 754. |
t.boolean() | Boolean | Represents true or false . |
t.string() | String | Represents 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:
- GraphQL input types when used as inputs to functions
- GraphQL object types in any other place.
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: