Navigate back to the homepage

Stand Up a Node.js Server with NestJS including TypeScript and GraphQL

Aryan Jabbari
September 18th, 2019 · 3 min read

Stand Up a Node.js Server with NestJS including TypeScript and GraphQL

Recently, I discovered NestJS and instantly fell in love. It is everything that I love about Angular (which includes TypeScript, the opinionated file structure, the modules, the decorators, and the dependency injection) in a Node framework. Additionally, it supports GraphQL.

Before We Get Started

This tutorial is not meant for beginners. It will not cover Node basics. If you’re looking to learn how Node and Express work, I made a series of videos where I create and deploy a basic timestamp microservice. Additionally, it will not cover GraphQL basics.

I made a video tutorial based off of this blog post. I suggest reading this blog post and watching the video as they complement each other well.

This tutorial uses nest-cli version 6.6.4 and was written on September 18th, 2019. If anything is out of date or to report any errors/blockers, please feel free to send me a tweet.

If at any point you feel lost, you can take a look at the final form of this code.

With all of that out of the way, let’s do this!

Getting Started with NestJS

NestJS is a Node.js framework that is compatible with both TypeScript and pure JavaScript. It comes with guard, pipe and interceptor support out-of-the-box. This makes it easy-to-use yet extremely powerful.

To get started, install the NestJS CLI. This allows you to easily create a new NestJS project.

1npm i -g @nestjs/cli
2nest new my-node-project

where my-node-project is the name of your Node project. If you have NPM and yarn installed, the NestJS will ask for your preference. If the project was created correctly, you should have a newly created project with the following structure:

1.
2├── README.md
3├── nest-cli.json
4├── package.json
5├── src
6│   ├── app.controller.spec.ts
7│   ├── app.controller.ts
8│   ├── app.module.ts
9│   ├── app.service.ts
10│   └── main.ts
11├── test
12│   ├── app.e2e-spec.ts
13│   └── jest-e2e.json
14├── tsconfig.build.json
15├── tsconfig.json
16├── tslint.json
17└── yarn.lock

Now go into that directory and run your newly created Node server:

1cd my-node-project
2npm run start:dev

Go to http://localhost:3000 (by default) to hit your “Hello World!” endpoint.

Sprinkle in GraphQL

GraphQL is a query language for APIs. NestJS uses their own GraphQLModule (imported from @nestj/graphql) which is a wrapper around the Apollo GraphQL server.

Before we get started, let’s remove the soon-to-be unused files (that were used for the “Hello World!” endpoint). More specifically, please delete src/app.controller.ts, src/app.service.ts, and their corresponding test files.

To get started with GraphQL and NestJS, install the necessary dependencies:

1npm i --save @nestjs/graphql apollo-server-express graphql-tools graphql

With these packages installed, register the GraphQLModule in /src/app.module.ts:

1import { Module } from '@nestjs/common';
2import { GraphQLModule } from '@nestjs/graphql';
3import { join } from 'path';
4
5@Module({
6 imports: [
7 GraphQLModule.forRoot({
8 definitions: {
9 path: join(process.cwd(), '/src/graphql.schema.d.ts'),
10 outputAs: 'class',
11 },
12 typePaths: ['./**/*.graphql'],
13 resolverValidationOptions: {
14 requireResolversForResolveType: false,
15 },
16 }),
17 ],
18})
19export class AppModule {}

I know, I know. There are tons of changes in here that I threw at you all. The NestJS GraphQL documentation does a fantastic job at explaining these changes. Here’s my take.

GraphQLModule.forRoot()

This registers the GraphQLModule with the server. The .forRoot() method takes an options object as an argument.

definitions

The @nestjs/graphql package automatically generates TypeScript defintions from the GraphQL schemas (see typePaths). We use the definitions object to configure the path where TypeScript definitions should be saved. By default, the GraphQL types are transformed to interfaces. I personally prefer classes which is what is seen in definitions.outputAs.

typePaths

typePaths tells the GraphQLModule where in the project to look for GraphQL files.

resolverValidationOptions

When running the server without resolverValidationOptions.requireResolversForResolveType equal to false, I get a warning similar to this one. Therefore, it’s false (for now).

Alright, back to GraphQL. Add src/schema.graphql to your project as follows:

1type Message {
2 id: Int!
3 description: String!
4}
5
6type Query {
7 messages: [Message]!
8}
9
10type Mutation {
11 createMessage(description: String!): Message!
12}

Restart your Node server, go to http://localhost:3000/graphql and you’ll see a GraphQL playground. Of course, any query or mutation you try running will end in an error as we’re yet to write our resolvers.

Writing a GraphQL Resolver with NestJS

Let’s write our first GraphQL resolver. Firstly, create a new NestJS module:

1nest generate module messages

This will import the MessagesModule into AppModule and create a new src/messages directory where the business logic for your Messages resolver will live (see what I was saying about NestJS’ modularity?).

Now, let’s create that resolver. We’ll create a dummy variable named messagesThatReallyShouldBeInADb that will function as our database and store all the messages and a GraphQL query that returns all the messages. In src/messages/messages.resolver.ts:

1import { Resolver, Query } from '@nestjs/graphql';
2
3@Resolver()
4export class MessagesResolver {
5 // this is just for demonstration purposes
6 // do NOT do this in real-life
7 // this is meant as a substitute for a databse
8 messagesThatReallyShouldBeInADb = [
9 { id: 0, description: 'The seed message' },
10 ];
11
12 @Query()
13 messages() {
14 return this.messagesThatReallyShouldBeInADb;
15 }
16}

Note the decorators NestJS provides us (Resolver and Query). This automagically maps to the messages query that we declared in src/schema.graphql. We must now provide this resolver to the MessagesModule. In src/messages.module.ts:

1import { Module } from '@nestjs/common';
2import { MessagesResolver } from './messages.resolver';
3
4@Module({
5 providers: [MessagesResolver],
6 exports: [MessagesResolver],
7})
8export class MessagesModule {}

Go to http://localhost:3000/graphql, refresh the pages, and run the messages query:

1{
2 messages {
3 description
4 }
5}

If everything was done correctly, you should see the seed message: GraphQL playground with the messages query and the returned messages array with the seed message

Now let’s add the createMessage mutation to src/messages/messages.resolver.ts. Remember the resolver type signature takes four arguments (parent, args, context, info). NestJS provides decorators for each argument. For this specific mutation, we use the @Args() decorator and pass it the name of the argument we want to access (description):

1import { Mutation, Resolver, Query, Args } from '@nestjs/graphql';
2
3@Resolver()
4export class MessagesResolver {
5 // this is just for demonstration purposes
6 // do NOT do this in real-life
7 // this is meant as a substitute for a databse
8 messagesThatReallyShouldBeInADb = [
9 { id: 0, description: 'The seed message' },
10 ];
11
12 @Query()
13 messages() {
14 return this.messagesThatReallyShouldBeInADb;
15 }
16
17 @Mutation()
18 createMessage(@Args('description') description: string) {
19 const id = this.messagesThatReallyShouldBeInADb.length;
20 const newMessage = { id, description };
21 this.messagesThatReallyShouldBeInADb.push(newMessage);
22 return newMessage;
23 }
24}

With the mutation added to the resolver, let’s return to our GraphQL Playground at http://localhost:3000/graphql and create some messages:

1mutation {
2 createMessage(description: "This is a witty description") {
3 description
4 }
5}

which should successfully return: GraphQL playground with the messages mutation and the returned message

Feel free to create a few messages using our new mutation and query for all messages.

Conclusion

With that, you now have a NestJS server complete with GraphQL, a simple GraphQL schema and a simple resolver for that schema (complete with a query and mutation). If you did everything correctly, the messages query and createMessage mutation should work as it does in this demo server. Again, if at any time you got lost and want to see the entire demo project, check out my GitHub repository.

The next step is to add a database to this stack. Prisma is an amazing solution that provides us with additional GraphQL and database tooling. In the next installment of this series, we will dive into using Prisma to save our messages.

If you liked this post, please support me by following me on Twitter, YouTube and GitHub.

📧 Join my email list and get notified about new content

Stay updated with all my blog posts and future randomness!

More articles from The WebDev Coach

The Case Against Print Statements in your Main Branch

The Case Against Print Statements in your Main Development Branch A coworker (who is new to our codebase) recently asked me to add print…

August 24th, 2019 · 4 min read

Concrete Steps to Get Off the Tutorial Treadmill

I recently received an email asking how to get off the tutorial treadmill : My tutorial treadmill blog post was admittedly vague and…

July 19th, 2019 · 2 min read
© 2018–2019 The WebDev Coach
Link to $https://twitter.com/aryanjabbariLink to $https://www.youtube.com/c/thewebdevcoachLink to $https://github.com/AryanJ-NYCLink to $https://www.linkedin.com/in/aryanjabbari