Migrating from Schemaless REST API to GraphQL without writing any code

Arda Tanrikulu
Migrating from Schemaless REST API to GraphQL without writing any code - The Guild Blog
Looking for experts? We offer consulting and trainings.
Explore our services and get in touch.

GraphQL was originally created in order to easily provide a powerful API on top of existing code. The current approach people are using today while migrating from REST API to GraphQL is to create a new schema and use GraphQL as a proxy. That has a lot of benefits because it gives us an opportunity to rethink the API and improve it, without changing the underlining services.

Let's first start with looking at that approach:

Implementing a basic proxy GraphQL backend

Let's say you have /user endpoint that does all CRUD operations for User entity with different HTTP methods, and you would need a GraphQL schema like below;

type Query {
  user(id: ID): User
}

type Mutation {
  createUser(input: UserInput): User
  updateUser(id: ID, input: UserInput): User
  deleteUser(id: ID): ID
}

type User {
  id: ID
  name: String
  age: Int
}

input UserInput {
  name: String
  age: Int
}

And you would also need a thin business logic that proxies upcoming GraphQL requests to the REST API using GraphQL resolvers like below;

module.exports = {
   Query: {
      user: (root, args) => fetch('https://myrest.com/user/' + args.id)
      .then(res => res.json())
   },
  Mutation: {
     createUser: (root, args) => fetch('https://myrest.com/user', {
       method: 'PUT',
       body: JSON.stringify(args.input)
      }).then(res => res.json()),
    updateUser:  (root, args) => fetch('https://myrest.com/user' + args.id, {
       method: 'POST',
       body: JSON.stringify(args.input)
    }).then(res => res.json()),
    deleteUser:  (root, args) => fetch('https://myrest.com/user' + args.id, {
       method: 'DELETE'
    }).then(res => res.json()),
};

This example assumes that you have /user/:id endpoint that gets a User entity with HTTP GET, deletes user with HTTP DELETE and updates a User that has the given id with the given input. Also /user endpoint creates a new User with the given input.

But this implementation will be hard to maintain when the REST API is updated and become bigger.

Using GraphQL Mesh instead without any code

GraphQL Mesh is a tool that handles multiple non-GraphQL data sources and generates an executable GraphQL schema on top of them with a simple configuration file. You can check the announcement blog post to learn more

On top of having handlers that automatically take care of sources with schema like - OpenAPI/Swagger, gRPC, SOAP, and others, it also has JSON Schema handler that generates a GraphQL Schema based on the given JSON schema files. This handler can also generate JSON Schema on runtime based on the given sample request and response data.

First you need to create a project using yarn on an empty directory:

yarn init

After that we need to install some dependencies of Mesh:

 yarn add @graphql-mesh/cli @graphql-mesh/json-schema graphql

Create a .meshrc.yml which is a configuration file for GraphQL Mesh on our new project:

sources:
  - name: MyRest
    handler:
      jsonSchema:
        baseUrl: https://myrest.com/
        operations:
          - type: Query
            field: user
            path: /user/{args.id}
            method: GET
            responseSample: ./getUserResponse.json
          - type: Mutation
            field: createUser
            path: /user
            method: PUT
            requestSample: ./createUserRequest.json
            responseSample: ./createUserResponse.json
          - type: Mutation
            field: updateUser
            path: /user/{args.id}
            method: POST
            requestSample: ./updateUserRequest.json
            responseSample: ./updateUserResponse.json
          - type: Mutation
            field: deleteUser
            path: /user/{args.id}
            method: DELETE
            responseSample: ./deleteUserResponse.json

As you can see in the configuration, we defined our endpoints without a single line of code. After creating this configuration file. We need to get sample request and response files by calling those endpoints on our local.

With a single command, our new GraphQL endpoint is ready to serve;

$ yarn mesh serve

Not only as a Gateway but also a completely type-safe SDK

Mesh is able to generate a type-safe SDK from generated GraphQL API because the generated GraphQL schema is a local GraphQLSchema that can be executed without binding an HTTP server.

That means you can use GraphQL Mesh inside your existing services or clients, as an SDK, just as a simple dependency, without adding another box in your architecture.