Migrating from Schemaless REST API to GraphQL without writing any code
Tags: graphql, rest, graphqlmesh
Published: 2021-07-29 09:55:51

> This article was published on Sunday, May 31, 2020 by [Arda Tanrikulu](https://twitter.com/ardatanrikulu) @ [The Guild Blog](https://the-guild.dev/)

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;

```graphql
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;

```js
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](/blog/graphql-mesh)

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:

```sh
yarn init
```

After that we need to install some dependencies of Mesh:

```sh
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:

```yaml filename=".meshrc.yml"
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;

```sh
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](https://graphql-mesh.com/docs/recipes/as-sdk), just as a simple dependency, without
adding another box in your architecture.