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
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:
In the
imports
array, let’s use theGraphQLModule
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-coreThen, in the
app/app.module.ts
file, change the emptyimports
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
andApolloDriverConfig
from@nestjs/apollo
, join frompath
, andApolloServerPluginLandingPageLocalDefault
fromapollo-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 thesrc/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 useApollo Sandbox
instead of thegraphql-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.
- By setting the autoSchemaFile property to
Then, let’s rename the
app.controller.ts
file toapp.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- Change the import of the controller, we no longer have one, we have a resolver instead
- Remove the
AppController
controller from thecontrollers
array, - Add the
AppResolver
in theproviders
array along withAppService
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.
- The
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
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 🚀
Kudos, our API is running, let’s now configure our database.