Skip to main content

From Rest to Graph

Currently, we have created a Rest API with one exposed endpoint, the GET defined in the src/app/app.controller.ts file, in this section, we will transition from the Rest API to Graphql API the painless way.

In our app.module.ts file, we have used the @Module decorator, diving into the Nest documentation, we understand that it provides metadata that Nest makes use of to organize the application structure, in other words, each Nest application has at least one Module to make it work, that we’ll call the root module, it’s our starting point, meaning, if we need to transform our API from Rest to Graph, we will need to detect and update our route module, in the way it starts listening only one endpoint, the graphql/.

Getting back to the module decorator, according to its documentation, a module can become a Provider to another module, all linked to the root module, the module-provider relationship is implementing a GRAPH data structure under the hood shown in the image below:

image3A - Application module-providers relationship from [THE NEST OFFICIAL DOC](https://docs.nestjs.com/)

image3A - Application module-providers relationship from THE NEST OFFICIAL DOC

The module decorator takes a single object as a set of properties that defines the module, we will use those properties to transform our API into a graphql, the most important ones for now are:

  • imports: the list of imported modules that export the providers which are required in this module.
  • providers: the providers that will be instantiated by the Nest injector and that may be shared at least across this module.
  • controllers: the set of controllers defined in this module that have to be instantiated.

Let’s go ahead and improve our root module so that our app will become a graphql app:

  1. In the imports array, let’s use the GraphQLModule exported from @nestjs/graphql package, after the required packages below.

    # install the required packages
    $ yarn add @nestjs/graphql @nestjs/apollo graphql apollo-server-express apollo-server-core

    Then, in the app/app.module.ts file, change the empty imports array to:

    // app/app.module.ts

    imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
    driver: ApolloDriver,
    autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
    playground: false,
    plugins: [ApolloServerPluginLandingPageLocalDefault()],
    }),
    ],

    With GraphQLModule imported from @nestjs/graphql, ApolloDriver and ApolloDriverConfig from @nestjs/apollo, join from path, and ApolloServerPluginLandingPageLocalDefault from apollo-server-core.

    In the GraphQLModule. we have added a couple of other properties:

    • By setting the autoSchemaFile property to join(process.cwd(), 'src/schema.gql'), we can use the code-first approach instead of the schema-first approach. This way, Nest will automatically generate our schemas based on our model classes. We've chosen to store the schema file in the src/schema.gql location, but you can also let Nest determine the location by simply setting autoSchemaFile to true. To learn more about the pros and cons of the schema-first vs code-first approach, you can check out this resource.
    • playground: set to false To use Apollo Sandbox instead of the graphql-playground as a GraphQL IDE for local development.
    • plugins: we need to define it as ApolloServerPluginLandingPageLocalDefault based on the playground value, if it’s set to true, we don’t necessarily need to add it as part of our plugins.
  2. Then, let’s rename the app.controller.ts file to app.resolver.ts and just enter the code below:

    // app/app.resolver.ts

    import { Query, Resolver } from '@nestjs/graphql';
    import { AppService } from './app.service';

    @Resolver()
    export class AppResolver {
    constructor(private readonly appService: AppService) {}

    @Query(() => String)
    getHello(): string {
    return this.appService.getHello();
    }
    }

    From the previous content, we can see these differences:

    • The @Controller decorator has been changed to @Resolver
    • The @Get decorator by @Query(() => String)

    But everything else remains exactly the same.

    Let’s now get back to our app.module.ts file, and fix the imports

    1. Change the import of the controller, we no longer have one, we have a resolver instead
    2. Remove the AppController controller from the controllers array,
    3. Add the AppResolver in the providers array along with AppService

    Our file now looks like the following:

    import { Module } from '@nestjs/common';
    import { AppResolver } from './app.resolver';
    import { AppService } from './app.service';
    import { GraphQLModule } from '@nestjs/graphql';
    import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
    import { join } from 'path';
    import { ApolloServerPluginLandingPageLocalDefault } from 'apollo-server-core';

    @Module({
    imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
    driver: ApolloDriver,
    autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
    playground: false,
    plugins: [ApolloServerPluginLandingPageLocalDefault()],
    }),
    ],
    controllers: [],
    providers: [AppService, AppResolver],
    })
    export class AppModule {}

    That way, we have transformed our initial Rest API into a Graphql one, in a few steps, easy to follow.

Let’s run the app once again and confirm that our API is now Graphql API

# Let's run the app in dev mode
$ yarn start:dev

Let’s go at http://localhost:3000/graphql

This is what we normally get:

image4A

image4A

Let’s query our server, we currently have only one Query, the getHello, if you were following along, everything should be running like on the image below

image4B - Our graphql API running 🚀

image4B - Our graphql API running 🚀

Kudos, our API is running, let’s now configure our database.