Apollo GraphQL Implementation in NestJs
Tags: nestjs, graphql, webdev, tutorial
Published: 2023-10-21 18:19:18

Today, we will be learning how we can implement the very basics of Apollo GraphQL in NestJs.

## What is GraphQL and why is GraphQL?
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data (definition from [https://graphql.org/](https://graphql.org/)). Before graphQL most web application (still) replies on REST Api as a channel between backend and frontend. 
The drawbacks of REST Api are: 

1. Over-fetching or Under-fetching: REST Api always sends back the same data structure for a given url. It could result in over-fetching, i.e getting more data than required by frontend, or under-fetching, i.e getting less data than required by frontend.

2. Multiple endpoints: Usually REST Api has multiple points, one for each type of data structure.

GraphQL solves both of these problems by: 

1. Allowing the client, frontend, to fetch the only data that is required. Frontend sends the structure of the data along with the request. And GraphQL only sends back the requested data.

2. GraphQL provide single endpoint, usually over /graphql route. Every query or mutation request is sent to this endpoint.

Now we have some idea what GraphQL is. Let's start implementing a GraphQL in NestJS.

## Setting up the project
1. First, we need to have nestjs/cli installed. Here is the command that will install the nestjs/cli: `npm i -g @nestjs/cli`

2. Once, we have installed nestjs cli, we can create a nest project by `nest new <project-name>`.

3. Then it will ask you the package manager that you want to use for this project, as shown below: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/18vmflshabktxnrz3pb1.png)

You can select any of them. For this project, I will go with npm. Now it will install some packages and make the directory structure for you. Once done, you would have the following directory structure:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wryf0oq9noxjqt2xtan8.png)

Our main focus of work would be /src directory. Before moving on, lets understand some basics of the files that you find inside /src directory:

**main.ts** is the root file and it is where the execution of project begins.

**app.controller.spec.ts** is the test file. *.spec.ts are used as tests. This would not be covered in this article. So we can delete it. 

**app.controller.ts** is the Controller file. Controllers are one which receives the incoming request, sends the request to Service, and returns the response backed to client. Controllers are the file where we define the api route and method for a specific data. You can read more about Controllers [here](https://docs.nestjs.com/controllers). 
**But** we are not going to use Controllers in our GraphQL server as Graphql uses Resolver (described later) rather than Controller.

**app.service.ts** is the Service. Services are responsible to handle all business logic for a particular data. It is usually responsible to fetch/alter the data from the database.

**app.module.ts** defines the module. In nestJs, Everything comes under some module. Whole code is sliced down in different modules. It is responsible to configure the structure of the application. 

4. Installing GraphQL
We can have either have **Express** or **Fastify** as our web framework. For this tutorial, we would go with Express.
Below is the command to install apollo graphQL:
`npm i @nestjs/graphql @nestjs/apollo @apollo/server graphql`

## Configuring Apollo GraphQL:
Open /src/app.module.ts and add GraphQL Module in imports like: 

```
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';

@Module({
  imports: [GraphQLModule.forRoot<ApolloDriverConfig>({
    driver: ApolloDriver,
    autoSchemaFile: true,
  })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```

The configuration of GrapqhQL, which is provided as an object in forRoot: 

```
{
    driver: ApolloDriver,
    autoSchemaFile: true,
}
```
You can read more about the configuration [here](https://docs.nestjs.com/graphql/quick-start#getting-started-with-graphql--typescript)

You might not be in the right directory. If not, move to your project directory by:
`cd <project-name>`

Now you can verify that graphQL server has been configured successfully by running the nest server by the following command: 
`nest start`

and open a browser and go to this url:
`localhost:3000/graphql`

You would see the grapqQL playground:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mvfyv60p6c9doylxmyij.png)

Playground is a place where you can test your APIs. We will use playground later in this tutorial when we will be done making some Queries and Mutations in Nest GraphQL Server.

## Implementing GraphQL
Now its time we start making GraphQL APIs. For that, we need to have some use case. So for this tutorial, we are going to have 2 entities, **Brands** and their related **Products**. 

### Brands

#### Module
First we are going to implement **Brands** module.  So to generate a module, you can type the following command in terminal: 
`nest g module brands`

This command will create a **Brands** directory inside /src with 'brands.module.ts' file.


#### Model
Now we want **Brands** model. Which will be a schema for **Brands**. There are 2 ways to have a schema, Schema First (through Schema Definition Language, SDL) and Code First. Lets pause the tutorial and understand these two first.

##### Difference between Schema First and Code First
These both approaches are used to make a schema. In Schema First, we define the schema, using SDL. 
Schema first approach looks like this:

```
type Brands {
  id: Int!
  name: String!
  logo: String
  type: String
}
```

The same thing can be done through Code First by:
```
import { Field, Int, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class Brands {
  @Field(() => Int)
  id: number;

  @Field()
  name: string;

  @Field({nullable: true})
  logo?: string;

  @Field({nullable: true})
  type?: string;
}

```

Here we are taking help from nestjs/graphql package which provides the required decorators and types.

Lets go through each thing one by one.

###### @ObjectType() decorator
**@ObjectType()** is used to define structure of the data. Here we are defining the structure of **Brands** which will have the above attribute.

###### @Field() decorator
**@Field()** is used to define a single attribute of the data. It has multiple over-loaders, one of which is takes a function as first parameter, like in the first field defined above: 
`@Field(() => Int)`
Here we are defining type of the id attribute would be Integer. 

**But why?** We haven't define the type of other fields in the @Field decorator, then why this? Well in TS, type number could be both integer and float. But in GraphQL, an attribute could either be Int or Float. So we have to explicitly tell Nest, that this field is of type Int.

We do not have to tell Nest explicitly about the string type. That is because string in TS corresponds to String in GraphQL.

We can also provide an object in the @Field decorator as: 
`@Field({nullable: true, defaultValue: "default"})`
Here you can define multiple things like whether the attribute can be null and what would be default value for that attribute. You can read more about @Field decorator [here](https://docs.nestjs.com/graphql/resolvers#object-types).

#### Back to Model
Now we need to make a model file in our /src/brands directory named:
**brands.model.ts**:
```
import { Field, Int, ObjectType } from '@nestjs/graphql';

@ObjectType()
export class Brands {
  @Field((type) => Int)
  id: number;

  @Field({ nullable: true })
  name?: string;
}
```

For now, we are going with two fields only. Later we will add another field, products, which link each brand to their products.

#### Service
Now we also want **Brands** service so we can handle all the business logic. To generate a service, here is the command: 
`nest g service brands`.

You would see 'brands.service.ts' in /src. We will alter that file to:
**brands.service.ts**:
```
import { Injectable } from '@nestjs/common';
import { Brands } from './brands.model';

@Injectable()
export class BrandsService {
  private readonly brands: Brands[] = [
    { id: 1, name: 'Adidas' },
    { id: 2, name: 'Nike' },
  ];
  findById(id: number): Brands {
    return this.brands.find((brand) => brand.id == id);
  }
  findAll(): Brands[] {
    return this.brands;
  }
  addBrand(id: number, name: string): Brands {
    this.brands.push({ id, name });
    return { id, name };
  }
}
```
##### @Injectable() decorator
@Injectable() is used to let Nest know that the class we are defining is injectable to other providers and controllers. By this, we can access the class instance through other classes. 

In Brands class, we have defined a variable brands. Usually this is to be done through database. Database is responsible for storing such data. But as we are not going to use any database in this tutorial, we are storing the data within the app. 

Furthermore, we have defined some function so fetch from and add to brands array.

#### Resolver
Rather than using Controller, which defines the API, we use Resolver in GraphQL. So make a file in /src/brands:
**brands.resolver.ts**:
```
import {
  Args,
  Int,
  Mutation,
  Query,
  Resolver,
} from '@nestjs/graphql';
import { Brands } from './brands.model';
import { BrandsService } from './brands.service';

@Resolver(() => Brands)
export class BrandsResolver {
  constructor(
    private brandsService: BrandsService,
  ) {}

  @Query(() => [Brands])
  getAllBrands(): Brands[] {
    return this.brandsService.findAll();
  }

  @Query(() => Brands)
  getBrandById(@Args('id', { type: () => Int }) id: number): Brands {
    return this.brandsService.findById(id);
  }

  @Mutation(() => Brands)
  addBrand(
    @Args('id', { type: () => Int }) id: number,
    @Args('name') name: string,
  ): Brands {
    return this.brandsService.addBrand(id, name);
  }
}
```

##### @Resolver() decorator
@Resolver decorator is used to define a resolver, a class which defines GraphQL Queries and Mutations, which client can use for requests. In @Resolver, we need to pass a function as the first parameter which returns the Object that this Resolver would resolve, in our case, it's Brands. 
`@Resolver(() => Brands)`

In the class BrandsResolver, we defined a constructor. Although we are not doing anything inside the block of constructor, but we are defining the BrandsService as brandsService by:
```
constructor(
    private brandsService: BrandsService,
  ) {}
```
Here we are injecting our BrandsService that we made before with @Injectable()

Next we are defining a GraphQL Query by:
```
@Query(() => [Brands])
  getAllBrands(): Brands[] {
    return this.brandsService.findAll();
  }
```

##### @Query() decorator
@Query is like the GET Api of REST, it takes first parameter as function which returns the **type** of the **return type of request**. In the above Query, we are returning Brands array back to the client when client calls this API.
Below it, we define a function, in which we fetch the Brands by using the BrandsService. Name of the function will be used as name of the Query.

After the queries, we are defining a mutation: 
```
@Mutation(() => Brands)
  addBrand(
    @Args('id', { type: () => Int }) id: number,
    @Args('name') name: string,
  ): Brands {
    return this.brandsService.addBrand(id, name);
  }
```

##### @Mutation() decorator
@Mutation is like the POST API of REST. It takes the first parameter as function, same as Query.
Below it, we define a function which can have any number of arguments. These variables are similar to body data in REST API. But we need to define these arguments through @Args decorator.

##### @Args() decorator
@Args is similar to @Field decorator that we learned earlier, except it takes first argument as name of argument and second as object which can define **type** and other things. 

Lastly, inside the function, we call the service class function to add brand by passing the arguments we got through @Args.

We are almost done with Brands. Just a single step remaining, we need to all the Services and Resolver in the **Brands** module by:
```
import { Module } from '@nestjs/common';
import { BrandsService } from './brands.service';
import { BrandsResolver } from './brands.resolver';

@Module({
  providers: [BrandsService, BrandsResolver],
})
export class BrandsModule {}
```

##### Brands API Testing
Now we have our **Brands** done. Let's test Brands API in playground. Open browser and go to `http://localhost:3000/graphql`
We can now see the **Docs** and **Schema** on the right side of playground.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1jugerrajd1bqigkms8n.png)

And we can test any API, like:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xfpp7vyumst7q02ix5zl.png)

### Products
Now lets quickly create Products Module to handle Products entity.

#### Module
Generate module by
`nest g module products`

#### Model
Create a file inside /src/products:
**products.model.ts**:
```
import { Field, Int, ObjectType } from '@nestjs/graphql';

@ObjectType()
export class Products {
  @Field((type) => Int)
  id: number;

  @Field({ nullable: true })
  name?: string;

  @Field((type) => Int)
  brandId: number;
}
```

We needed to add brandId as well to link the Brands with their Products, we are using one-many relationship here.

#### Service
Generate service by `nest g service products`.
**products.service.ts**:
```
import { Injectable } from '@nestjs/common';
import { Products } from './products.model';

@Injectable()
export class ProductsService {
  private readonly products: Products[] = [
    {
      id: 1,
      name: 'Product A',
      brandId: 1,
    },
    {
      id: 2,
      name: 'Product B',
      brandId: 1,
    },
    {
      id: 3,
      name: 'Product C',
      brandId: 2,
    },
  ];

  findById(id: number): Products {
    return this.products.find((product) => product.id == id);
  }

  findByBrandId(brandId: number): Products[] {
    return this.products.filter((product) => product.brandId == brandId);
  }

  addProduct(id: number, name: string, brandId: number): boolean {
    this.products.push({ id, name, brandId });
    return true;
  }
}
```

#### Resolver
Make a file in /src/products:
**products.resolver.ts**:
```
import { Args, Int, Mutation, Query, Resolver } from '@nestjs/graphql';
import { Products } from './products.model';
import { ProductsService } from './products.service';

@Resolver(() => Products)
export class ProductsResolver {
  constructor(private productsService: ProductsService) {}
  @Query((returns) => [Products])
  getProductsByBrandId(
    @Args('brandId', { type: () => Int }) brandId: number,
  ): Products[] {
    return this.productsService.findByBrandId(brandId);
  }
  @Query((returns) => Products)
  getProductById(@Args('id', { type: () => Int }) id: number): Products {
    return this.productsService.findById(id);
  }
  @Mutation((returns) => Boolean)
  addProduct(
    @Args('id', { type: () => Int }) id: number,
    @Args('name') name: string,
    @Args('brandId', { type: () => Int }) brandId: number,
  ): boolean {
    return this.productsService.addProduct(id, name, brandId);
  }
}
```

Modify the
**products.module.ts**:
```
import { Module } from '@nestjs/common';
import { ProductsService } from './products.service';
import { ProductsResolver } from './products.resolver';

@Module({
  providers: [ProductsService, ProductsResolver],
})
export class ProductsModule {}
```

### Linking Products to Brands

Here we need to modify some of the files of Brands Module. First of all, we need to pass ProductsService in providers of Brands so that we can use ProductsService to find the Products related to a Brand by using `findByBrandId` function that we defined in ProductsService class above.

**brands.module.ts**:
```
import { Module } from '@nestjs/common';
import { BrandsService } from './brands.service';
import { BrandsResolver } from './brands.resolver';
import { ProductsService } from 'src/products/products.service';

@Module({
  providers: [BrandsService, BrandsResolver, ProductsService],
})
export class BrandsModule {}
```

We also need to add a field in Brands Model as **products** which will corresponds to Brands products
**brands.model.ts**:
```
import { Field, Int, ObjectType } from '@nestjs/graphql';
import { Products } from 'src/products/products.model';

@ObjectType()
export class Brands {
  @Field((type) => Int)
  id: number;

  @Field({ nullable: true })
  name?: string;

  @Field((type) => [Products], { defaultValue: [] })
  products?: Products[];
}
```

Lastly, we need to Resolve this newly added field in Brands Resolver,
**brands.resolver.ts**:
```
import {
  Args,
  Int,
  Mutation,
  Parent,
  Query,
  ResolveField,
  Resolver,
} from '@nestjs/graphql';
import { Brands } from './brands.model';
import { BrandsService } from './brands.service';
import { Products } from 'src/products/products.model';
import { ProductsService } from 'src/products/products.service';

@Resolver(() => Brands)
export class BrandsResolver {
  constructor(
    private brandsService: BrandsService,
    private productsService: ProductsService,
  ) {}

  @ResolveField()
  products(@Parent() brand: Brands): Products[] {
    const brandId = brand.id;
    return this.productsService.findByBrandId(brandId);
  }

  @Query((returns) => [Brands])
  getAllBrands(): Brands[] {
    return this.brandsService.findAll();
  }

  @Query((returns) => Brands)
  getBrandById(@Args('id', { type: () => Int }) id: number): Brands {
    return this.brandsService.findById(id);
  }

  @Mutation((returns) => Brands)
  addBrand(
    @Args('id', { type: () => Int }) id: number,
    @Args('name') name: string,
  ): Brands {
    return this.brandsService.addBrand(id, name);
  }
}
```

##### @ResolveField() decorator
We have added a @ResolveField decorator in the resolver file. When we have an object, **Object A**, as a field of other object, Object B, like Products as a field for Brands, we need to resolve that field, that is to define a way through which **Object A** is fetched on some link attribute. Here linking attribute is Brand ID. Brand ID is **id** in **brands.model.ts** and **brandId** in **products.model.ts**.

In the function provided after decorator, requires first argument as parent object, i.e Brands here. And we define it using @Parent decorator like:
```
...
...
@ResolveField()
  products(@Parent() brand: Brands)
...
...
```
We can access Brands Id by brand.id and pass it to the ProductsService findByBrandId function.

That's it. Save everything and re run the server by:
`nest start`

Go to playground and verify that we can access Products of each Brands:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mhiffwn0g690oefegd3a.png)


---

That's a wrap. Hope you found this article helpful.
You can access the repo [here](https://github.com/kito-arch/NestJs-Apollo).
Keep learning ❤️