Create a GraphQL API using your existent REST API with NodeJS and Typescript

This is the second part of a GraphQL with Node and Typescript series, to check the first part and learn why GraphQL is the natural evolution of REST for app-oriented APIs please refer to my previous article.

Moving from REST to GraphQL

Did you decide to move forward from REST because GraphQL is better than REST for app-oriented APIs?

Oh, don't worry, it’s not like you need to throw your existing REST API into the garbage can, I am going to show you you can add a GraphQL Layer on top of your existing REST API.

For the sake of having a running API that we can control and modify let's create a very simple REST API.
This API will have three entities, Product, Category, and Measurement Unit.

This is how a Product will look like in our Data Model.

Each Product has an ID referencing Category and MeasurementUnit entities.

This is how a Category will look like.

And finally, this is how a Measurement Unit will look like.

You can find the fully working API in this repository.
Let’s take a look at the relevant parts of the REST API code.

This REST API is written in typescript but it could be any existing API written in any programming language, as long as you can reach it from your GraphQL Server you will be fine

src/app.ts

Nothing fancy here, we just create an Express server and launch it on the PORT 4000.

Our REST Routes

There are six routes on this small API.

src/routes.ts

The API is reading the data from a JSON file to make the code easy and simple, in a real-world app, the data source could be a SQL or NoSQL database, another API, or whatever source we have defined.

if we, for example, hit the endpoint

GET /api/products

We will obtain the list of all the Product entities.

Our REST API is ready, we won’t add more CRUD methods to keep this API simple and small, but it could contain as many methods and entities as we want.

Creating the GraphQL API on top of our existing REST one

You can see the end result code of the GraphQL API here.

The idea here is to leverage the existing REST API and create a GraphQL API that will reuse our code and business logic.

To create the GraphQL Layer we will use the awesome framework TypeGraphQL which makes the creation of GraphQL APIs with NodeJS, Apollo Server, and Typescript very straightforward.

Similar to the creation of our REST API we create an Express HTTP server but this time we are mounting an Apollo Server instance as middleware of the Express instance.

src/app.ts

This is pretty standard for creating a GraphQL Server with NodeJS, Typescript, and Express.

The GraphQL Schema Resolvers are defined in the schema.ts file.

src/schema.ts

We talked about a Resolver, but what is that and how does it work?

Well in GraphQL, unlike REST, we don’t have endpoints, we have Queries, Mutations, and Subscriptions, and each one of those is mapped to a piece of our code where it will resolve the operation performed. So a resolver is basically a function that will return data that corresponds to the defined Schema Queries, Mutations, and Subscriptions.

Let’s create our first TypeGraphQL Resolver.

The Object Type Class

src/resolvers/product.resolver.ts

Let's analyze this code piece by piece, first, we are creating a Product class that has all the properties that we will receive from our REST API with its corresponding Typescript types.

Then we decorate our class with the @ObjectType() decorator, this tells TypeGraphQL that we intend for this class to be an Object Type in our GraphQL Schema.

Then we decorate each property of the class with the @Field() decorator, this tells TypeGraphQL that we intend for this property to be exposed on our schema as a Field of the Product.

It’s not required for all properties to be exposed to the GraphQL layer, we could only expose a couple of fields and not the rest of them.

The Resolver Class

The next thing we create is a class with two methods. The first one will return the list of all Products, and the second one will allow us to get a single Product by id.

Then we need to decorate such methods with the @Query() decorator to tell TypeGraphQL that we want each one of these methods to be exposed as Queries to the GraphQL schema and pass the Object Type that we are returning as a result of the query as an argument to the decorator.

src/resolvers/product.resolver.ts

The first method will return an array of Products, while the second one will return a single Product.

Also, the second one needs the ID of the Product as an argument, and that’s the reason why we add that argument to the function and decorate it with the @Arg() giving the argument the “id” name.

And finally, inside the body of each method, we perform the HTTP call to our existing REST API and return the result of the call.

All we need to do now is repeat the same for the Category and Measurement Unit entities.

src/resolvers/category.resolver.ts
src/resolvers/measurement-unit.resolver.ts

Finally, we add our resolvers to the schema.ts file.

And with that, we can execute the command npm start and start using our GraphQL API.

all products query
product by id query

Relationship between Entities

Our GraphQL API now works, but it isn’t really that different from the REST API, we have 6 Queries with data unrelated to each other, in the REST version we had 6 endpoints doing pretty much the same.

One of the most useful features about GraphQL is that our Schema Entities are related to each other, for example, it would be useful if we could know the category of a product or the list of products that belong to a specific category in a single Query.

Let’s add a category to our products.

Product’s Category

TypeGraphQL allows us to define a resolver for an individual field of an ObjectType.

To do that we need to create a class decorated with @Resolver() but this time we have to send the ObjectType as an argument for the Resolver.

src/resolvers/product.resolver.ts

And inside that class we will add the category resolver function, that needs to be decorated with the @FieldResolver() decorator.

src/resolvers/product.resolver.ts

This category resolver function will take the product to which we want to get the category as a root argument, and for that reason, we decorate that argument with the @Root() decorator.

This means that, when it’s trying to get the category for a given product, the product itself is available to us on the field resolver code, as you can see, we are using the categoryId field of the product to call the REST API and get the category that we need to return.

And now we can do the same for our product’s measurement units. This is how our Product Resolver file will look like at the end.

src/resolvers/product.resolver.ts

Now all we need to do is register our new resolver in the schema.ts file

src/schema.ts

And now we can start querying the category of a product.

all products query with category
product by id query with category

Now let’s do something similar with the categories, but this time we want to be able to query all the products that belong to a given category.

src/resolvers/category.resolver.ts

What this field resolver does is get all the products and return the ones that belong to the given category.

We need to add the new resolver class to the schema.ts file

src/schema.ts

With that, we can query all the products of a category.

all categories query with all products that belong to each category
single category by id with all products that belong to that category

Conclusion

As you see, it is perfectly possible to create your own GraphQL API on top of an existing REST API, and from there on you can continue growing your API on the GraphQL layer while maintaining your old REST API and get all the advantages of using a GraphQL API vs a REST API.

If you want to create GraphQL APIs using node and typescript in a couple of minutes. Make sure to check out the awesome framework MerlinGQL at https://www.npmjs.com/package/@merlin-gql/cli

If you enjoyed my story or want to give me feedback, you can reach me on https://twitter.com/EzequielZacca

Passionated Software Engineer - I would like to share my knowledge, but specially my love for software development and engineering

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store