This repo demonstrates how to use the graphQL code-based
pothos (formerly named giraphql
) library to build queries,
mutations, subscriptions, and add directives.
It also includes sample jest
tests.
It is written using Typescript.
Components:
- pothos
- Apollo Server
- Apollo Server Express
- graphql-ws for subscriptions and as a testing client for subscriptions
- Sequelize ORM w/ sqlite
- sequelize-typescript for defining
sequelize
models - dataloader-sequelize as a dataloader provider for
sequelize
- graphql-playground
- graphql-codegen to generate the schema file and typescript definitions for frontend consumption, along with a fully-typed GQL client
node.js v14 is the baseline requirement.
$ yarn
$ yarn dev
The server will start on port 3000
.
- GQL API:
http://localhost:3000/graphql
- Playground: http://localhost:3000/playground
Run unit tests with:
$ yarn test:unit
Integration tests:
$ yarn test:integration
You can use the graphql-codegen
generated files with your frontend for type information when calling the server.
$ yarn generate
Generated files are located in the gql-schema
directory.
The following plugins are used:
In the src/
folder:
datasources/
: Apollo datasources for making db callsdb/
: Sequelize modelsgql/
:pothos
definitions
The gql/
folder is organized by domain. The reason I've done this vs organizing
by queries or mutations is the following:
pothos
is a code-based gql definition library. Because it's code-based, you have a lot of control on how to define your graphQL items. The trade-off is that it's more verbose. If you were to shove everything under a single query or mutation file, it would be extremely difficult to navigate and read.- Types themselves can have multiple resolvers that are independent of a query or mutation and can alone be quite verbose / complex.
- It's easier to find files that are specific to the function in an IDE. For example, the post creation mutation can be easily discovered in file search.
- All the code for that specific function lives in a single file makes it easier to bounce back and forth from vs jumping between files.
Here's some queries to try out in the playground:
Create a user and post:
mutation {
createUser(input: {
name:"Theo Gravity"
}) {
user {
id
}
}
createPost(input:{
authorId: 1
title:"Test title",
content:"Test post"
}) {
id
}
}
Query for user posts:
query {
user(id: 1) {
id
name
posts {
id
title
content
created
}
}
}
Get users:
query {
users {
id
name
}
}
Get posts:
query {
posts {
id
title
content
created
author {
name
}
}
}