Table of contents
- Introduction
- Objective
- Organize resolvers and type-def
- Generate resolvers type
- Resolvers type verifications
Introduction
Before we get started, it’s high recommend to clone the Github repo and we can follow along with the article contents.
The first step after we downloaded the repo is to checkout the the starter folder and run npm install
to install the necessary dependencies
Objective
Below are the directory of our start pack in this tutorial, where each modules have been organized in a different folder.
- 03-graphql-server-typescript
- data
- index.ts
- modules
- schema.ts
- tsconfig.json
- package-lock.json
- package.json
Our goal in this tutorial are:
- Merge each of the resolvers and type-defs into modules/index.ts file
- Generate the type for the resolvers to ensure it is type safe.
Organize resolvers and type-def
We would need install a few dependency to help us speed up the process, which are:
Here is the command snippet you can copy to install these dependencies:
npm install @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-resolvers -D
Once these packages are ready, we could then proceed to merge our GraphQL resolvers and type-defs under modules/index.ts file
import { mergeResolvers, mergeTypeDefs } from "@graphql-tools/merge";
import { makeExecutableSchema } from "@graphql-tools/schema";
import { sport } from "./sport";
import { user } from "./user";
const modules = [sport, user];
const resolvers = mergeResolvers(
modules.flatMap((m) => (m.resolvers ? [m.resolvers] : []))
);
export const typeDefs = mergeTypeDefs(modules.map((m) => m.typeDefs));
export const schema = makeExecutableSchema({
resolvers,
typeDefs,
});
Then we could specified our schema
into our GraphQL server under the index.ts file.
import { ApolloServer } from "apollo-server";
import { schema } from "src/modules";
const server = new ApolloServer({
schema: schema,
});
server.listen().then(({ url }) => {
console.log(`GRAPHQL server is running at ${url}`);
});
Explaination
- If we take a look on one of the module index file, we are basically an object which contains it’s
resolvers
andtypeDefs
, we then import them into the module’s index file and start doing the merging process. - As you can see, we have a filtering process when we are merging the resolvers by using flatMap to avoid any potential error if the resolver is not existed in any of the file.
- We can then merge our resolvers and type-defs by using
mergeResolvers
andmergeTypeDefs
methods which then allows us to create our GraphQL schema by inputting these parameters and usingmakeExecutableSchema
method. - Once our
schema
is ready, we could then connect it into our GraphQL Apollo server which replaced thetypeDefs
andresolvers
fields input. - Now, we should we able to run our GraphQL server locally without getting any error.
Generate resolvers type
Before we start relying on GraphQL codegen
to generate our GraphQL resolvers type, we would need to define some rules under the codegen.yml
file.
We can create a codegen.yml
file in the root directory which parked under the same level of package.json
, package-lock.json
and tsconfig.json
.
Here will be the content of our codegen.yml
file:
schema: ./src/schema.ts
require:
- ts-node/register/transpile-only
- tsconfig-paths/register
generates:
./src/modules/schema.d.ts:
plugins:
- "@graphql-codegen/typescript"
- "@graphql-codegen/typescript-resolvers"
We could also update our package.json
file to include the code generator command:
{
...
"scripts": {
...
"prestart": "npm run codegen",
"codegen": "graphql-codegen"
},
}
Explaination
- We first need to specify the location of our entire
typeDefs
of each module which is stored under the schema.ts file. - Adding dependencies into the
require
field is to make sure GraphQL codegen actually picks up these dependencies when generating the types. In this case, this is to avoid the Typescript path alias andimport
keyword issue.- Adding
ts-node
is for make sure it doesn’t get import issue when referring src/schema.ts as it’s the same directory level of graphql server (index.ts) - Adding
tsconfig-paths/register
to make sure the graphql-codegen doesn’t get path alias error when refering the src/modules/*/resolvers files
- Adding
- We can then specified the location of type generated file which is
/src/modules/schema.d.ts
in this case under thegenerates
field with the necessary plugins which are@graphql-codegen/typescript
and@graphql-codegen/typescript-resolvers
to support the Typescript in GraphQL resolvers. - Adding
codegen
command in package.json allows us to generate our type in anytime when we ran this command, while addingprestart
command is to make sure our Apollo GraphQL server retrieved the latest version of the Resolver type before the server got started.
Resolvers type verifications
Once the codegen
command has been run successfully, you should able to see there is a file called schema.d.ts
generated under the modules
directory.
We could then assign the resolver type in each of the modules. For example:
import { Sports } from 'src/data/initial';
import { Resolvers } from '../schema';
export const resolvers:Resolvers = {
Query: {
...
},
Mutation: {
...
},
};
import { Users } from 'src/data/initial';
import { Resolvers } from '../schema';
export const resolvers:Resolvers = {
Query: {
...
},
Mutation: {
...
},
};
Once we have defined our resolver type, we should immediately get a type error as the following:
Types of property 'id' are incompatible. Type 'number' is not assignable to type 'string'
This is a advantage of using Typescript rather than Javascript to avoid any potential issue in the dev environment. The GraphQL ID type is refers to a STRING type but not a INTEGER type and the ID in our returned data is a INTEGER.
To solve this, we have prepared a new set of data where the id
field is now in a STRING type. We could easily update our data directory from src/data/initial
to src/data/final
and it would resolve the issue