Harnessing the power of TypeScript & GraphQL
GraphQL is a powerful query language for APIs and a runtime for fulfilling those queries with your existing data. It's an elegant approach that solves many problems typically found with REST APIs. For background, we suggest reading this comparison between GraphQL and REST. GraphQL combined with TypeScript helps you develop better type safety with your GraphQL queries, giving you end-to-end typing.
In this chapter, we assume a basic understanding of GraphQL, and focus on how to work with the built-in
@nestjs/graphql module. The
GraphQLModule is a wrapper around the Apollo server. We use this proven GraphQL package to provide a way to use GraphQL with Nest.
Start by installing the required packages:
info Hint If using Fastify, instead of installing
apollo-server-express, you should install
Nest offers two ways of building GraphQL applications, the code first and the schema first methods. You should choose the one that works best for you. Most of the chapters in this GraphQL section are divided into two main parts: one you should follow if you adopt code first, and the other to be used if you adopt schema first.
In the code first approach, you use decorators and TypeScript classes to generate the corresponding GraphQL schema. This approach is useful if you prefer to work exclusively with TypeScript and avoid context switching between language syntaxes.
In the schema first approach, the source of truth is GraphQL SDL (Schema Definition Language) files. SDL is a language-agnostic way to share schema files between different platforms. Nest automatically generates your TypeScript definitions (using either classes or interfaces) based on the GraphQL schemas to reduce the need to write redundant boilerplate code.
Getting started with GraphQL & TypeScript
Once the packages are installed, we can import the
GraphQLModule and configure it with the
forRoot() static method.
forRoot() method takes an options object as an argument. These options are passed through to the underlying Apollo instance (read more about available settings here). For example, if you want to disable the
playground and turn off
debug mode, pass the following options:
As mentioned, these options will be forwarded to the
The playground is a graphical, interactive, in-browser GraphQL IDE, available by default on the same URL as the GraphQL server itself. To access the playground, you need a basic GraphQL server configured and running. To see it now, you can install and build the working example here. Alternatively, if you're following along with these code samples, once you've complete the steps in the Resolvers chapter, you can access the playground.
With that in place, and with your application running in the background, you can then open your web browser and navigate to
http://localhost:3000/graphql (host and port may vary depending on your configuration). You will then see the GraphQL playground, as shown below.
Another useful feature of the
@nestjs/graphql module is the ability to serve multiple endpoints at once. This lets you decide which modules should be included in which endpoint. By default,
GraphQL searches for resolvers throughout the whole app. To limit this scan to only a subset of modules, use the
In the code first approach, you use decorators and TypeScript classes to generate the corresponding GraphQL schema.
To use the code first approach, start by adding the
autoSchemaFile property to the options object:
autoSchemaFile property value is the path where your automatically generated schema will be created. Alternatively, the schema can be generated on-the-fly in memory. To enable this, set the
autoSchemaFile property to
By default, the types in the generated schema will be in the order they are defined in the included modules. To sort the schema lexicographically, set the
sortSchema property to
A fully working code first sample is available here.
To use the schema first approach, start by adding a
typePaths property to the options object. The
typePaths property indicates where the
GraphQLModule should look for GraphQL SDL schema definition files you'll be writing. These files will be combined in memory; this allows you to split your schemas into several files and locate them near their resolvers.
You will typically also need to have TypeScript definitions (classes and interfaces) that correspond to the GraphQL SDL types. Creating the corresponding TypeScript definitions by hand is redundant and tedious. It leaves us without a single source of truth -- each change made within SDL forces us to adjust TypeScript definitions as well. To address this, the
@nestjs/graphql package can automatically generate TypeScript definitions from the abstract syntax tree (AST). To enable this feature, add the
definitions options property when configuring the
The path property of the
definitions object indicates where to save generated TypeScript output. By default, all generated TypeScript types are created as interfaces. To generate classes instead, specify the
outputAs property with a value of
The above approach dynamically generates TypeScript definitions each time the application starts. Alternatively, it may be preferable to build a simple script to generate these on demand. For example, assume we create the following script as
Now you can run this script on demand:
info Hint You can compile the script beforehand (e.g., with
tsc) and use
nodeto execute it.
To enable watch mode for the script (to automatically generate typings whenever any
.graphql file changes), pass the
watch option to the
To automatically generate the additional
__typename field for every object type, enable the
To generate resolvers (queries, mutations, subscriptions) as plain fields without arguments, enable the
A fully working schema first sample is available here.
Accessing generated schema
In some circumstances (for example end-to-end tests), you may want to get a reference to the generated schema object. In end-to-end tests, you can then run queries using the
graphql object without using any HTTP listeners.
You can access the generated schema (in either the code first or schema first approach), using the
info Hint You must call the
GraphQLSchemaHost#schemagetter after the application has been initialized (after the
onModuleInithook has been triggered by either the
When you need to pass module options asynchronously instead of statically, use the
forRootAsync() method. As with most dynamic modules, Nest provides several techniques to deal with async configuration.
One technique is to use a factory function:
Like other factory providers, our factory function can be async and can inject dependencies through
Alternatively, you can configure the
GraphQLModule using a class instead of a factory, as shown below:
The construction above instantiates
GraphQLModule, using it to create options object. Note that in this example, the
GqlConfigService has to implement the
GqlOptionsFactory interface, as shown below. The
GraphQLModule will call the
createGqlOptions() method on the instantiated object of the supplied class.
If you want to reuse an existing options provider instead of creating a private copy inside the
GraphQLModule, use the