Using GraphQL Paper with GraphQL
GraphQL Paper is built on the core graphql
library and works well with its default resolvers. GraphQL Paper should also work well with other javascript systems that use resolver functions, too. The best integrations will still be with graphql-mocks
and its packages which are designed and tested together.
If using GraphQL Paper with graphql-mocks
check out the guide dedicated to setup, common patterns and techniques.
Example
Here is an example of GraphQL Paper working with the core graphql
package
Schema
The full Querying and Mutating examples below make use of the following schema:
const graphqlSchema = `
schema {
query: Query
mutation: Mutation
}
type Query {
films: [Film!]!
film(filmId: ID!): Film
}
type Mutation {
addFilm(input: AddFilmInput!): Film!
}
type Film {
id: ID!
title: String!
year: String!
actors: [Actor!]!
}
type Actor {
id: ID!
name: String!
}
input AddFilmInput {
title: String!
year: String!
actors: [AddFilmActorInput!]!
}
input AddFilmActorInput {
name: String!
}
`;
// kick everything off
export default graphqlSchema;
Querying
To resolve queries in a GraphQL Resolver return data from the paper.data
property on a Paper
instance. The GraphQL Paper Querying Data documentation provides more information on how to retrieve data with GraphQL Paper.
GraphQL Paper also provides connections between different types and their corresponding documents out of the box which allows for the resolution of resolvers to work recursively. To kick off this behavior return the appropriate Document or list of Documents from the top-level Query
resolvers.
Complete Query Example
In this example returning the resolvers for a list of [Film!]
from the Query.films
or a single Film
by ID from Query.film
will also satisify any queries that request a film's Actor
s by returning the actors
connections on the Film
document.
Using the graphql
npm package with the above schema for an end-to-end example involving queries.
import schemaString from "./schema";
import { Paper } from "graphql-paper";
import { graphql, buildSchema } from "graphql";
async function run() {
const graphqlSchema = buildSchema(schemaString);
const paper = new Paper(graphqlSchema);
await paper.mutate(({ create }) => {
create("Film", {
id: "1",
title: "Jurassic Park",
year: "1993",
actors: [
{ id: "1", name: "Jeff Goldblum" },
{ id: "2", name: "Wayne Knight" },
],
});
create("Film", {
id: "2",
title: "Office Space",
year: "1999",
actors: [
{ id: "3", name: "Ron Livingston" },
{ id: "4", name: "Jennifer Aniston" },
],
});
});
const queryType = graphqlSchema.getQueryType();
const queryTypeFields = queryType.getFields();
queryTypeFields.films.resolve = function filmsResolver(
root,
args,
context,
info
) {
// return all `Film` Documents
return paper.data.Film;
};
queryTypeFields.film.resolve = function filmResolver(
root,
args,
context,
info
) {
return paper.data.Film.find((film) => film.id === args.filmId) ?? null;
};
const query = `
query {
film(filmId: "1") {
id
title
year
actors {
id
name
}
}
films {
id
title
year
# will return the connected Actor documents automatically
actors {
id
name
}
}
}
`;
const result = await graphql({
source: query,
schema: graphqlSchema,
});
console.log(result);
}
// kick everything off!
run();
{ "data": { "film": { "actors": [ { "id": "1", "name": "Jeff Goldblum" }, { "id": "2", "name": "Wayne Knight" } ], "id": "1", "title": "Jurassic Park", "year": "1993" }, "films": [ { "id": "1", "title": "Jurassic Park", "year": "1993", "actors": [ { "id": "1", "name": "Jeff Goldblum" }, { "id": "2", "name": "Wayne Knight" } ] }, { "id": "2", "title": "Office Space", "year": "1999", "actors": [ { "id": "3", "name": "Ron Livingston" }, { "id": "4", "name": "Jennifer Aniston" } ] } ] } }
Mutating
Mutations also work with GraphQL Paper and graphql
. The GraphQL Paper Mutating Data documentation provides more information on how mutating data with GraphQL Paper.
Returning from Mutations
If a document can satisfy a mutation's expected return type then return it from paper.mutate
. In this example if the mutation field returns a GraphQL Type of SomeType
then
async function createSomeTypeMutationResolver(root, args, context, info) {
// return the paper.mutate
return paper.mutate(({ create }) => {
// return the created SomeType Paper Document
return create('SomeType', { /* use data from args... */ });
});
}
If the result is not satisfied by the document the result can be awaited and modified as needed. Assuming in this example the mutation payload only required the payload with the ID
{ someTypeId: newId }
Then the mutation resolver could look like:
async function createSomeTypeMutationResolver(root, args, context, info) {
// return the paper.mutate
const someTypeDocument = await paper.mutate(({ create }) => {
// return the created SomeType Paper Document
return create('SomeType', { /* use data from args... */ });
});
// take the resulting document and returning the required shape
return {
someTypeId: someTypeDocument.id
};
}
Complete Mutation Example
Using the graphql
npm package with the above schema for an end-to-end example using mutations.
import schemaString from "./schema";
import { Paper } from "graphql-paper";
import { graphql, buildSchema } from "graphql";
async function run() {
const graphqlSchema = buildSchema(schemaString);
const paper = new Paper(graphqlSchema);
const mutationType = graphqlSchema.getMutationType();
const mutationTypeFields = mutationType.getFields();
mutationTypeFields.addFilm.resolve = function filmsResolver(
root,
args,
context,
info
) {
return paper.mutate(({ create, getStore }) => {
const store = getStore();
const maxIdReducer = (previous, { id }) =>
Math.max(Number(previous), Number(id)).toString();
let lastFilmId = store.Film.reduce(maxIdReducer, "0");
let lastActorId = store.Actor.reduce(maxIdReducer, "0");
const newFilm = create("Film", {
id: ++lastFilmId,
title: args.input.title,
year: args.input.year,
});
newFilm.actors = args.input.actors.map((actor) => {
return create("Actor", {
id: ++lastActorId,
...actor,
});
});
return newFilm;
});
};
const mutation = `
mutation($addFilmInput: AddFilmInput!) {
addFilm(input: $addFilmInput) {
id
title
year
actors {
id
name
}
}
}
`;
const mutationInput = {
title: "My Girl",
year: "1991",
actors: [{ name: "Anna Chlumsky" }],
};
const result = await graphql({
source: mutation,
schema: graphqlSchema,
variableValues: { addFilmInput: mutationInput },
});
console.log(result);
}
// kick everything off!
run();
{ "data": { "addFilm": { "actors": [ { "id": "1", "name": "Anna Chlumsky" } ], "id": "1", "title": "My Girl", "year": "1991" } } }