GraphQL and PostGraphile with NestJS


So far I have explained a few latest technologies related to the NodeJS microservices such as NestJS, TypeORM, BullJS with Angular as the client. I will go through a couple of other things in this article.  Until now I have used a REST API for uploading files. Here are the previous articles related to this article.

  1. File uploading example using NestJS and Angular 11 - Part 1
  2. File uploading example using NestJS and Angular 11 - Part 2
  3. Use Bull with NestJS
  4. Introduction to PostGraphile

In this article, I am going to use GraphQL. If you are familiar with REST, you might find a few drawbacks of using REST. According to the requests of the client application, you may have to create many APIs, sometimes all those APIs look similar except for a single attribute. Sometimes the client requests some specific data, but your API provides many attributes even though they are irrelevant to the client's request. These issues are known as Over fetching (Too much data) and Under fetching (Not enough data). This is a common disadvantage of using REST. GraphQL is introduced to overcome over fetching, under fetching, and the creation of too many APIs.


What is GraphQL?

  • Developed by Facebook in 2012 and initially released in 2015.
  • This is a query language for creating APIs
  • GraphQL is the specification, not an implementation
  • It will use a single endpoint and the client can choose what data is required.
  • Actually, this allows clients to define what they exactly required.
  • Another important thing is, GraphQL can expose data from multiple resources. This is extremely faster than calling REST APIs.
  • GraphQL supports most of the popular programming languages. 
  • There are multiple GraphQL clients are available for each language. You can find more details from the GraphQL official documentation.


Use GraphQL with NestJS


NestJS provides @nestjs/graphql module. This is a wrapper around the Apollo server. In this article, I am going to use this module for the backend. NestJS offers two ways to create GraphQL applications.
  • Code first
  • Schema first

You may choose the best one according to the situation. In the schema first method, you need to create the schema. In the code first method, your code will generate a schema for you. I will mention here the basic idea about both methods. Anyway, I will use Code first method to develop our application. 


Schema-first

  • First, create the schema and the code follows the schema
  • The Schema Definition Language is used to write schema, 
  • This approach is very formal and makes better APIs
  • This approach reduces the development time because both frontend and backend developers can work in parallel without waiting.

Code first

  • In this scenario, the schema is defined and implemented programmatically.
  • This keeps both schema definitions and resolvers.
  • This is best if your schema is growing.
  • But less readable.

Install GraphQL module for NestJS

  • NestJS provides a GraphQL module for easy development.
  • According to the documentation, it is required to install four packages
    • @nestjs/graphql
    • graphql-tools
    • graphql
    • apollo-server-express
  • Just hit the following command to install all.

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


GraphQL Playground

The GraphQL Playground is an in-browser graphical IDE to run and test GraphQL APIs. You can create your GraphQL API and then you can get the output. Another specific thing is, you can access the schema and docs as well. Please check the below screenshot.



What is next?


Up to now, I have created a REST API to save the uploaded CSV files to Postgres DB.  I will use GraphQL to view, edit, delete and search operations on stored data. Let's create one by one and begin with View data operation using GraphQL.


Configure NestJS application to work with GraphQL


We need to add module details to app.module.ts. Please refer below code.



        import { Module } from '@nestjs/common';
        import { GraphQLModule } from '@nestjs/graphql';
        import { AutomobileModule } from './automobile/automobile.module';
        import { DatabaseModule } from './database/database.module';

        @Module({
        imports: [
        AutomobileModule,
        DatabaseModule,
        GraphQLModule.forRoot({
        autoSchemaFile: 'schema.gql'
        })],
        controllers: [],
        providers: [],
        })
        export class AppModule {}




As you can see, I am going to generate the schema file (schema.gql) This file will consist of Queries, Mutations, and object types. As I use the code first method, I need to create object types, queries, and mutation and then the NestJS will generate the schema file for me.


Modify entity class


I have already created an entity called a Vehicle in the previous article. I will refactor it here.


        import { Field, Int, ObjectType } from "@nestjs/graphql";
        import { Column, Entity, PrimaryColumn } from "typeorm";

        @Entity('vehicle')
        @ObjectType()
        export class Vehicle{

        @Field(type => Int)
        @PrimaryColumn()
        private id: number;

        @Field(type => String, { nullable: true })
        @Column('varchar')
        private make: string;

        @Field(type => String, { nullable: true })
        @Column('varchar')
        private model: string;

        @Field(type => String, {nullable: true})
        @Column('varchar')
        private year: string;

        @Field(type => String, { nullable: true })
        @Column('varchar')
        private engineNumber: string;

        }


I have added @ObjectType() decorator for the class and @Field() decorator, for fields. This will generate the Vehicle object type in the schema file. But still, your application will not start. It will give the following error.


GraphQLError [Object]: Query root type must be provided.


Apollo server requires at least one @Query() to make it a valid GraphQL server. To add @Query or @Mutations we need to create a resolver


Create a resolver

Resolver gives instructions to a GraphQL server and the client will interact with @Query and @Mutation in the resolver. This looks similar to the Controller but actually not. You may read the documentation for more details because my focus is to demonstrate, how to do it practically. 

An application can have many resolvers. I am going to create a single resolver with a @Query to get vehicle details from the database. We can use @Mutation decorators to, save, delete and update operations. I used PostGraphile to make easy and better communication between service and database. Here is my resolver.


        import { Args, Int, Mutation, Query, Resolver } from "@nestjs/graphql";
        import { Vehicle } from "./vehicle";
        import { request, gql } from 'graphql-request';

        @Resolver(() => Vehicle)
        export class AutomobileResolver {

        @Query(() => [Vehicle])
        async vehicles() {

        const query = gql`query MyQuery {
        allVehicles {
        nodes {
        id
        make
        engineNumber
        model
        year
        }}}`

        return request('http://localhost:5000/graphql', query).then((data) => {
        return data.allVehicles.nodes;
        });
        }
        }



In the PostGraphile article, I have explained how it communicates with each other. In our client application(Modifications in the client application are yet to be complete) it talks with the GraphQL server which is running on port 3000 (http://localhost:3000/graphql) in the NestJS application. Then it talks with the PostGraphile endpoint through the NestJS application. Here I used the graphql-request library to communicate with the PostGraphile endpoint. To install it, please hit the below command.

npm add graphql-request graphql


@Resolver decorator will make the class as a resolver. @Query decorator is to explain a query, this is for GET operations. If you are doing POST, PATCH and DELETE operations, you can use @Mutation for that. In the vehicles() query, there is a graphical query, this query can be extracted from the PostGraphile playground. Check this for more info about PostGraphile.

Once you create a resolver and then start the NestJS application. Then it will create a schema.gql file for you, as we mentioned in the app.module.ts file. You should not edit this, because it is automatically generated according to the code first approach. Now your service is ready. Let's move on to the client application.


Configure Angular application to work with GraphQL


Now we need to do several things to configure the client application.
  • Install the Apollo client
  • Create a component to view the data
  • Create an entity class to handle the entity
  • Change nav-bar component 
  • Add routes to view the data.

Install the Apollo client


Please hit the following command to install the Apollo client in Angular. 


ng add apollo-angular


It may ask a few questions while installing. Check the below screenshot for a clear understanding. I have used http://localhost:3000/graphql as the GraphQL endpoint. This can be changed later.




Create a component to view the data


Hit the following command to create a component in the vehicle directory to view data.


ng g c vehicle/view


Then added a simple table to view data in the view.component.html file.

        <div style="margin: 1%; padding: 2%;">
        <table class="table table-hover">
        <thead>
        <tr>
        <th scope="col">ID</th>
        <th scope="col">Car make</th>
        <th scope="col">Car model</th>
        <th scope="col">Year</th>
        <th scope="col">Engine Number</th>
        </tr>
        </thead>
        <tbody>
        <tr *ngFor="let vehicle of vehicles">
        <td>{{vehicle.id}}</td>
        <td>{{vehicle.make}}</td>
        <td>{{vehicle.model}}</td>
        <td>{{vehicle.year}}</td>
        <td>{{vehicle.engineNumber}}</td>
        </tr>
        </tbody>
        </table>
        </div>


Here is the view.component.ts file with a query to get data from the GraphQL server.


        import { Component, OnInit } from '@angular/core';
        import { Apollo, gql, QueryRef } from 'apollo-angular';
        import { Vehicle } from 'src/app/vehicle/vehicle.entity';

        export const GET_VEHICLES = gql`
        query{
        vehicles{
        id
        make
        model
        year
        engineNumber
        }
        }`

        @Component({
        selector: 'app-view',
        templateUrl: './view.component.html',
        styleUrls: ['./view.component.css']
        })
        export class ViewComponent implements OnInit {

        vehicles: Vehicle[] = [];
        vehicle !: Vehicle;
        private query !: QueryRef<any>;

        constructor(private apollo: Apollo) { }

        ngOnInit(): void {
        this.getVehicles();
        }

      getVehicles() {
       this.query = this.apollo.watchQuery({
        query: GET_VEHICLES, fetchPolicy: 'no-cache'
      });
      this.query.valueChanges.subscribe(result => {
        this.vehicles = result.data && result.data.vehicles;
       })
       }
        }


I will explain this a little bit. The GET_VEHICLES query can be created in the GraphQL playground. Once the NestJS service is ready with the above configuration, you will be able to connect to the graphical server on http://localhost:3000/graphql. You can see the schema and the docs on the right side and it can be used to write the query. Please refer to the screenshot above in the GraphQL playground section.

Here I used apollo.watchQuery (You can use query as well) and subscribed it to retrieve data from the GraphQL server.


Create an entity class to handle the entity


Here is the entity class that I am using throughout this application. 

        export class Vehicle{
        id!: number;
        make!: string;
        model!: string;
        year!: string;
        engineNumber!: string;
        }


Change nav-bar component 

Add the following line into the current list in the menu

        <li><a [routerLink]="'/vehicles'" routerLinkActive="active">Vehicles</a></li>


Add routes to view the data.


Add the following route in the routes array in the app-routing.module.ts file.

          {
        path: 'vehicles',
        pathMatch: 'full',
        component: ViewComponent
        }


See the demo


If everything is completed, Start the redis-server, NestJS server, PostGraphile and Angular client application. Then you will be able to see the data as below once you clicked on Vehicles tab.






Part 05: CRUD operations with GraphQL and NestJS







GraphQL and PostGraphile with NestJS GraphQL and PostGraphile with NestJS Reviewed by Ravi Yasas on 2:43 AM Rating: 5

No comments:

Powered by Blogger.