GraphQL in NestJS: A Concise 5-Minute Guide
Tags: webdev, graphql, nestjs, backend
Published: 2024-03-26 20:46:49

This guide will help you set up GraphQL in your NestJS application. It will cover the installation, configuration, and basic usage of GraphQL with NestJS. 

## Why GraphQL over REST?
In traditional REST APIs, you might end up over-fetching or under-fetching data. Over-fetching is when the client downloads more information than is actually needed in the app. Under-fetching is when a specific endpoint doesn’t provide enough of the required information. The client will need to make additional requests to fetch everything it needs. But with GraphQL, you can ask for exactly what you need and get just that. This makes GraphQL efficient.
## Repo Link: https://github.com/Subham-Maity/scalable_server_architecture/tree/main/example/2.%20graphql_typeorm/schema-first-approach

## Approach : Schema First Approach 

- This article is based on schema first approach you can check this one for [Code First Approach](https://dev.to/codexam/nestjs-graphql-code-first-approach-1pn0)

## Installation

- Install the required dependencies using npm:

```bash
npm install @nestjs/graphql @nestjs/apollo @apollo/server graphql
```
These packages are necessary to set up a GraphQL server. `@nestjs/graphql` is a NestJS module for GraphQL, `@nestjs/apollo` is a NestJS module for Apollo, `@apollo/server` is a community-driven, open-source GraphQL server, and `graphql` is the JavaScript reference implementation for GraphQL.

## Configuration

1. **Import GraphQLModule**

- Open the `app.module.ts` file and import the `GraphQLModule`.

```typescript
import { ApolloDriverConfig, ApolloDriver } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { BookResolver } from './book/book.resolver';

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      playground: true, // Set to false in production. It enables the GraphQL Playground where you can test your queries.
      typePaths: ['./**/*.graphql'], // Specify the location of GraphQL files. It tells the server where to find our type definitions.
    }),
    BookResolver, // Import the resolver. Resolvers handle the incoming GraphQL queries.
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}
```

## Usage

Follow these steps to create a basic GraphQL module, resolver, and schema:

1. **Create a Module**

- Create a new module for your GraphQL entities (e.g., `book.module.ts`).

```typescript
import { Module } from '@nestjs/common';
import { BookResolver } from './book.resolver';

@Module({
  imports: [],
  controllers: [],
  providers: [BookResolver], // Import the resolver. Resolvers are responsible for defining how the fields in the schema are populated.
})
export class BookModule {}
```

2. **Create a Resolver**

- Create a new resolver for your GraphQL queries and mutations (e.g., `book.resolver.ts`).

```typescript
import { Query, Resolver } from '@nestjs/graphql';

@Resolver('Book')
export class BookResolver {
  @Query('books')
  getAllBooks() {
    return [
      {
        id: 1,
        title: 'Book 1',
        author: 'Author 1',
        price: 10,
      },
      {
        id: 2,
        title: 'Book 2',
        author: 'Author 2',
        price: 20,
      },
      {
        id: 3,
        title: 'Book 3',
        author: 'Author 3',
        price: 30,
      },
    ];
  }
}
```
In the above code, `@Resolver('Book')` is a decorator that defines `Book` as a GraphQL object type, and `@Query('books')` is a decorator that defines a GraphQL query to fetch all books.

3. **Create a GraphQL Schema**

- Create a new GraphQL schema file (e.g., `book.schema.graphql`).

```graphql
type Book {
  id: ID!
  title: String!
  price: Int!
}

type Query {
  books: [Book]
}

type Mutation {
  addBook(title: String!, price: Int!): Book
}
```
This schema defines a `Book` type, a query to fetch all books, and a mutation to add a new book.

## Testing

1. **Start the NestJS Server**

- Run the NestJS server and navigate to `http://localhost:3000/graphql`.

2. **Open the GraphQL Playground**

- You should see the GraphQL Playground interface.

3. **Execute a Query**

- Enter the following query in the playground:

```graphql
{
  books {
    price
    title
  }
}
```

4. **View the Result**

- Click the "Play" button, and you should see the following result:

```json
{
  "data": {
    "books": [
      {
        "price": 10,
        "title": "Book 1"
      },
      {
        "price": 20,
        "title": "Book 2"
      },
      {
        "price": 30,
        "title": "Book 3"
      }
    ]
  }
}
```

This guide covers the basic setup and usage of GraphQL with NestJS. You can extend this example by adding more complex types, queries, and mutations based on your application's requirements.

## Compare (Optional) 

let's compare the syntax for CRUD operations in REST with Mongoose/Prisma and GraphQL:

1. **Create (POST in REST)**

- REST with Mongoose:
```javascript
app.post('/books', async (req, res) => {
  const book = new Book(req.body);
  await book.save();
  res.status(201).send(book);
});
```
- GraphQL:
```graphql
mutation {
  createBook(title: "New Book", author: "Author Name") {
    id
    title
    author
  }
}
```

2. **Read (GET in REST)**

- REST with Mongoose:
```javascript
app.get('/books', async (req, res) => {
  const books = await Book.find({});
  res.send(books);
});
```
- GraphQL:
```graphql
query {
  books {
    id
    title
    author
  }
}
```

3. **Update (PUT in REST)**

- REST with Mongoose:
```javascript
app.put('/books/:id', async (req, res) => {
  const book = await Book.findByIdAndUpdate(req.params.id, req.body, { new: true });
  res.send(book);
});
```
- GraphQL:
```graphql
mutation {
  updateBook(id: "1", title: "Updated Book") {
    id
    title
    author
  }
}
```

4. **Delete (DELETE in REST)**

- REST with Mongoose:
```javascript
app.delete('/books/:id', async (req, res) => {
  const book = await Book.findByIdAndDelete(req.params.id);
  res.send(book);
});
```
- GraphQL:
```graphql
mutation {
  deleteBook(id: "1") {
    id
    title
    author
  }
}
```

5. **Read a Single Item (GET in REST)**

- REST with Mongoose:
```javascript
app.get('/books/:id', async (req, res) => {
  const book = await Book.findById(req.params.id);
  res.send(book);
});
```
- GraphQL:
```graphql
query {
  book(id: "1") {
    id
    title
    author
  }
}
```

In GraphQL, you can see that the operations are more concise and we can specify exactly what data we want to get back, which can lead to performance improvements. In REST, the server determines what data is sent back in each request, which can lead to over-fetching or under-fetching of data. However, REST can be simpler to use for simple APIs and doesn't require a schema definition like GraphQL does. Both have their uses depending on the situation.