Queries, Mutations and Subscriptions
Queries, mutations, and subscriptions are fields on the schema's root types. Each root type has methods for defining the type, adding one field, and adding several fields.
Queries
Use builder.queryType() to define the Query type. This example returns plain backing data through
an object reference:
import SchemaBuilder from '@pothos/core';
type Giraffe = { name: string };
const builder = new SchemaBuilder({});
const giraffes: Giraffe[] = [{ name: 'James' }];
const GiraffeRef = builder.objectRef<Giraffe>('Giraffe').implement({
fields: (t) => ({
name: t.exposeString('name'),
}),
});
builder.queryType({
fields: (t) => ({
hello: t.string({
resolve: () => 'hello, world!',
}),
giraffes: t.field({
type: [GiraffeRef],
resolve: () => giraffes,
}),
}),
});Define the Query type once. To split its fields across files, use builder.queryField() or
builder.queryFields(). The following is an alternative to the builder.queryType() call above,
using the same builder, object reference, and data:
builder.queryType({});
builder.queryField('hello', (t) =>
t.string({
resolve: () => 'hello, world!',
}),
);
builder.queryFields((t) => ({
giraffes: t.field({
type: [GiraffeRef],
resolve: () => giraffes,
}),
}));Mutations
Use builder.mutationType(), builder.mutationField(), and builder.mutationFields() in the same
way. Continuing the query example, this mutation adds a giraffe to the array returned by giraffes:
builder.mutationType({});
builder.mutationField('createGiraffe', (t) =>
t.field({
type: GiraffeRef,
args: {
name: t.arg.string({ required: true }),
},
resolve: (_parent, args) => {
const giraffe = { name: args.name };
giraffes.push(giraffe);
return giraffe;
},
}),
);
const schema = builder.toSchema();The required argument provides a string for the backing model's name. This example stores data
in memory; an application can perform its database write in the resolver instead.
mutation {
createGiraffe(name: "Morgan") {
name
}
}A subsequent { giraffes { name } } query returns both James and Morgan.
Subscriptions
Use builder.subscriptionType(), builder.subscriptionField(), and builder.subscriptionFields()
to define subscription fields. Each field has a subscribe function that returns an async iterable
of events, and a resolve function that converts each event into the field's result.
This separate example defines the context contract for a counter and its event provider. Supply a
shared counter and provider through your server's context so the mutation publishes to the same
stream that subscriptions consume. The provider's subscribe() method must register the listener
when called and release it when the returned iterator is closed.
import SchemaBuilder from '@pothos/core';
type Context = {
count: { value: number };
counterEvents: {
publish: (value: number) => void;
subscribe: () => AsyncIterable<number>;
};
};
const builder = new SchemaBuilder<{ Context: Context }>({});
builder.queryType({
fields: (t) => ({
count: t.int({
resolve: (_parent, _args, context) => context.count.value,
}),
}),
});
builder.mutationType({
fields: (t) => ({
incrementCount: t.int({
resolve: (_parent, _args, context) => {
context.count.value += 1;
context.counterEvents.publish(context.count.value);
return context.count.value;
},
}),
}),
});
builder.subscriptionType({
fields: (t) => ({
incrementedCount: t.int({
subscribe: (_parent, _args, context) => context.counterEvents.subscribe(),
resolve: (count) => count,
}),
}),
});
const schema = builder.toSchema();Start a subscription before calling the mutation to receive its event:
subscription {
incrementedCount
}mutation {
incrementCount
}With an initial count of 0, the mutation returns 1 and the subscription emits
{ "data": { "incrementedCount": 1 } }. Configure a subscription transport in your GraphQL server
to deliver these results to clients.
Define subscribe before resolve so TypeScript can infer the resolver's event type.