You've successfully subscribed to WorldRemit Technology Blog
Great! Next, complete checkout for full access to WorldRemit Technology Blog
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info is updated.
Billing info update failed.
GraphQL: Introducing Your New BFF (Backend-For-Frontend)

GraphQL: Introducing Your New BFF (Backend-For-Frontend)

. 5 min read

| Image by Michael Dziedzic via Unsplash Copyright-free

What is GraphQL?

GraphQL is a query language for an API, as well as a server-side runtime for executing queries. By prioritising the clients and giving them exactly what they ask for, GraphQL is designed to make APIs flexible, fast and developer-friendly.

Before we start… The basics

GraphQL allows you to create a schema, where you can define all the possible data that clients can query through your API. It can be seen as a “contract” between the server and the client. A schema contains object types, which define the objects and all the fields that a client can ask for. The fields are typed and can be marked as “non-nullable” (with the symbol !), which means that the server will throw an error if a null value is returned for that field.

An object type for Country:

type Country {  
    id: ID! *// This is a GraphQL scalar type that represents IDs.*   
    code: String!  
    name: String!  
    short_name: String!  
    poster: String!  
    dial_code: Int  
    en_name: String
}

Every field in a schema is attached to a function, which is called a resolver. A resolver knows how to fetch the data and provide a value for its field during query execution. It can optionally take 4 positional arguments: ‘parent’, ‘args’, ‘context’ and ‘info’, which allow you to pass things that a resolver might need (learn more about the arguments here).

A resolver in a “resolver map” object:

const resolvers = {  
    Query: {    
        user(parent, args, context, info) {      
            return users.find(user => user.id === args.id);    
        }  
    }
}

A query is a way to get data from the GraphQL server. When a client makes a query, GraphQL validates the query against the schema and executes it.

A query for countries data:

query {  
    countries {    
        id    
        code    
        name  
    }
}

A mutation is a way to modify data. It handles any operations that change data on the server, such as creating, updating, deleting, or triggering other business processes.

A mutation for logging in a user:

mutation {  
    login(data: { email: "gql@test.com", password: "12345"}) {    
         tokenType    
         accessToken  
    }
}

A subscription is a way to maintain a real-time connection with a server, and keep your app updated with any changes that it’s subscribed to. It has the same syntax as queries and mutations. The example below will allow a client to subscribe to a new user created in the backend:

subscription {  
    userCreated {    
        id    
        name    
        email  
    }
}

Why use GraphQL?

GraphQL is becoming a popular alternative to REST, with advantages such as:

  • No more over and under-fetching of data
  • API evolution without versioning & automatic documentation
  • Predictable data structure through defined types and schemas
  • Ability to merge data from multiple sources with a single request

A growing number of organisations are embracing GraphQL as a way to unify their data in a single graph, or as an “API gateway” for facilitating their microservices architecture. At WorldRemit, we have started to adopt GraphQL as a Backend-For-Frontend (BFF) service that can interact with multiple microservices, each dedicated to a single domain. With the different rewrite projects happening for the mobile clients and other systems, it’s been a great opportunity to assess the benefits and best practices for using GraphQL in various scenarios.

Our experiences so far have shown us that by leveraging the power of GraphQL as a middleware, we’re able to expose the data from different APIs to clients in a more predictable way, and to quickly aggregate data from multiple sources to meet the clients' needs.

GraphQL has various tools and SDKs that support multiple languages, so you can set up your API in many different ways. Our GraphQL API is developed in Node.js with TypeScript and below are a couple of useful tools that have helped us to build a more robust and scalable API.

Apollo Server

It’s common to use a library with GraphQL to do all the heavy lifting and make things easier for developers. Apollo is a widely used, full-featured library, with both a client and a server library. Apollo Server is a tool that we have used to build our API in Node.js, and it handles all the different client requests via a single endpoint. Apollo Server can be used as a stand-alone GraphQL server or be added on to an existing Node.js middleware. In our case, our Apollo Server sits on top of AdonisJS, which gives us added benefits of some of its features and allows us to add additional routes to the API. You can use Apollo Server to talk directly to the database or to act as an API Gateway. We use it as a gateway to talk to some of the existing REST APIs at WorldRemit, which allows the services to be left untouched and continue to be accessed by clients. Apollo Server also has some additional features such as caching, and can be easily scaled to create a GraphQL Federation.

TypeGraphQL

TypeScript and GraphQL use strong typing, which helps to make our code less error-prone, more readable and predictable. However, developing a GraphQL API with TypeScript can be a little tricky, because the GraphQL types defined in a GraphQL schema are not supported on the resolvers, which are regular functions. In order to use those type definitions, we have to also represent them using TypeScript classes or interfaces. This creates code redundancy and it can get difficult to maintain the consistency between the schema and the resolvers. TypeGraphQL is a library that can address this problem by making it easier to define the schema using classes and a bit of decorator magic. Some of the syntax for defining types and resolvers might look different to the standard GraphQL way, but it uses the same concepts under the hood. What’s great is that it allows creating the entire GraphQL API using TypeScript!

Data Aggregation

One of the biggest strengths of GraphQL is that it can merge data from multiple services and return it to the client in the exact shape that they want. We were able to implement such data aggregation for a requirement from the mobile clients - to retrieve accepted currencies for each destination of a sender country.

It’s quite simple to aggregate data and attach it to the existing model, without affecting the downstream services. Combined with the ability for the client to request the exact data that they need, GraphQL can meet the clients’ requirements in a flexible and efficient way.

What’s next?

GraphQL Federation

With GraphQL, you can have one graph that represents the whole enterprise-wide model. However, having a single monolithic graph that clients can call to fetch data might not be ideal in a microservices architecture, where you have multiple teams across different domains and a risk for the graph to become unmanageable. With GraphQL Federation, we can divide our graph into multiple domains (subgraphs), which can come together in a single Supergraph or Federated Graph. Each team/domain will be able to work independently and modify the graph, while still being connected to the main graph. There are different methods to achieve this, with the Apollo Federation as a popular framework. We’re also discovering ways to make it easier for teams to create their own GraphQL subgraph by using a custom CLI generator. It’s still early days in our progress but we’re excited about the potential!

Useful resources

We hope this introduction has helped you learn a little more about GraphQL and how it could help to manage data better. As with everything, GraphQL may not be the ideal approach for every scenario, and it has its own limitations. But ultimately, we’re excited to leverage GraphQL by adapting it to the different needs of the company and help to build a more flexible and efficient API.