Intro
Today we will talk about wrapping a REST API with a GraphQL wrapper, which means that the REST API will be accessible via a different GraphQL API. We’ll be using Apollo Server for the implementation. This article assumes you have a basic understanding of REST API endpoints, and some knowledge of GraphQL. Here is the code repo if you want to review it while reading. With that said, we will be looking at why you would wrap a REST API, how to wrap an existing REST API, and how you can enhance your data using GraphQL.
Why wrap a REST API with GraphQL
There are a couple of different reasons to wrap a REST API. The first is migrating from an existing REST API, which you can learn about in detail here, and the second is creating a better wrapper for existing data.
Granted, this can be done using REST. But for this article, we will focus on a GraphQL version. A reason for creating a better wrapper would be using a CMS that provides custom fields. For instance, you get a field that is listed as C_435251, and it has a value of 532. This doesn’t mean anything to us. But when looking at the CMS these values could indicate something like “Breakfast Reservation” is set to “No”. So, with our wrapping, we can return it to a more readable value. Another example is connecting related types. For instance, in the code repo for this blog, we have a type Person with a connection to the type Planet.
Connection example
type Person {
"""The name of this person."""
name: String
"""A planet that this person was born on or inhabits."""
homeworld: Planet
}
type Planet {
"""The name of this planet."""
name: String
}
How to Wrap a REST API
Alright, you have your REST API, and you might wonder how to wrap it with GraphQL? First, you will call your REST API endpoint, which is inside your rest-api-sources file inside your StarwarsAPI class.
REST API example
class StarwarsAPI {
constructor() {
this.axios = axios.create({
baseURL: 'https://swapi.dev/api/',
});
}
async getPerson(id) {
const {
data
} = await this.axios.get(`people/${id}`);
return data
}
async getHomeworld(id) {
const {
data
} = await this.axios.get(`planets/${id}`);
return data
}
}
This above class will then be imported and used in the server/index file to set up your new Apollo server.
Apollo server example
const StarwarsAPI = require('./rest-api-sources/starwars-rest-api');
const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => ({}),
context: () => {
return {
starwarsAPI: new StarwarsAPI(),
};
},
});
Now, in your GraphQL resolver, you will make a person query and retrieve your starWarsAPI from it, which contains the information you want to call. GraphQL resolver
const resolvers = {
Query: {
person: async (_, {
id
}, {
starwarsAPI
}) => {
return await starwarsAPI.getPerson(id);
},
},
};
With the above done, let's start on how to enhance your data in the resolver.
Enhancing your data
With our resolver up and running, we’ll now use it to enhance some of our data. For now, we’ll make the name we get back returned in a first name, and the last initial format. To do so above our Query, we’ll start a Person object and put the variable name inside it. We’ll then grab the name from our Query and proceed to tweak it into the format we want.
Enhancing in resolver
Person: {
name: ({
name
}) => {
if (!name) {
return null;
}
const [first, last] = name.split(" ")
if (last === undefined) {
return first
}
return `${first} ${last[0].toUpperCase()}.`
}
},
Tada! Now, when we call our GraphQL, our name will return formatted in a first name, and last initial state.
Conclusion
Today's article covered why you want to wrap a REST API with GraphQL for migration or to provide a better API layer, how to wrap an existing REST API with GraphQL, and how you can use the resolver to enhance your data for things like name formatting. I hope it was helpful, and will give others a good starting point.
If you want to learn more about GraphQL and REST API wrappers, read up on our resources available at graphql.framework.dev.