DEV Community

Convert REST APIs to GraphQL with AWS AppSync

REST APIs

We all have been using REST APIs for a long time now. REST = REpresentation STate. Requests from client are replied with a representation of the state of the resource using HTTP, in one of the uniform formats like JSON. Client and server sends messages back and forth with the representations for changing the state.

Disadvantages of REST API

REST API may give you more data you need.
Each REST API may be a different endpoint and/or managed separately
Multiple calls are required to get required data.

You can see examples for these here: Github Guide to migrate from REST to GraphQL

GraphQL

Created in 2012 and made public in 2015 by Facebook, GraphQL addresses many of the drawbacks of REST API.

  • You can get just the data you need and nothing more.
  • Single Endpoint structure - no need to manage multiple APIs.
  • Built-in caching, batching, pagination.

Your own REST APIs you may be able to re-write in GraphQL paradigm, but what if you were using an API that was not controlled by you? AWS Appsync provides you a way to convert a REST API to GraphQL API.

AWS AppSync

AWS AppSync is a managed GraphQL service that makes it easy to connect disparate data sources into a single cohesive API. You define schema that tells what type of data is available and how to query them. Data Sources are the backend services that the API will use to fulfill requests. Resolvers connect data sources with queries and types in schema (and mutations)

Our REST API

Our REST API is hosted on AWS API Gateway. It will give you the picture of a random cat image url from the internet. Didn't we invent internet to send each other cat pics?

REST API on AWS API Gateway

AppSync API

We will get into Appsync and create an API. Select "Build from scratch". Make sure to click the button on the top, the below button is for a different selection.

API From Scratch

Now inside this API, select Data Sources and create Data Source. Select HTTP Endpoint and give the hostname of the API Endpoint.

HTTP Endpoint

Now our Cat API gives a response like below:

   {
        url: "https://i.imgur.com/7X8uJZX.jpg"
    }
Enter fullscreen mode Exit fullscreen mode

Inside the API in Appsync, goto Schema and create a schema to describe and query the data from the API.

type Query {
    getURLJSON: AWSJSON
    getURL: String
}

type imgurl {
    url: String
}
Enter fullscreen mode Exit fullscreen mode

type Query shows a GET in REST speak. and type imgurl defines a object type called imgurl which can be compared to a model with attributes. Here we have only one field within the object type. We have not included Mutation here, which is graphql method for modifying server-side data. (POST etc.)

Resolver

In the schema screen itself, on the resolver side, click on the attach button near the getURL query.

Resolver

Resolver provides a way to map the details in your HTTP request so that it can be mapped to what is needed on the REST API. AWS defaults resolvers to use javascript based pipeline resolvers. This allows you to have a pipeline of functions that will process your request data or response data as it flows through the pipeline. This provides more power at the cost of complexity. We will be doing this the easy way today to illustrate our use case.

Click on Actions -> Update Runtime -> Change Resolver Type - Unit Resolver -> Select Runtime (VTL)

Unit Resolver will have one before mapping template and after mapping template. VTL stands for Velocity Template Language, a language by Apache for writing templates. Before mapping template will process your request date before it sends to the REST API endpoint. After mapping template will process the data coming from REST API, when it comes from the resolver. VTL also provides facility to add a function if needed.

Below is a diagram that compares Unit Resolvers and Pipeline Resolvers. (Left side shows the Unit Resolver)

Resolvers

This image is (c) AWS and from this documentation

Our before template:

{
    "version": "2018-05-29",
    "method": "GET",
    "resourcePath": "/default/random-cat-api"
}
Enter fullscreen mode Exit fullscreen mode

It specifies the HTTP verb to be used (GET) and the resource path which will be appended to the url we gave in the data source definition.

Our after template:

$util.toJson($ctx.result.body) 
Enter fullscreen mode Exit fullscreen mode

This just takes the REST API output and converts to JSON. This is required since our REST API was built in dinosaur times and returns a String. If your REST API returns JSON like the good ones, you just use $ctx.result.body

Our resolver will look like:
Resolver

Now how to query this GraphQL API? AppSync provides a Query section for testing out queries. Goto the query section inside the API. Here you define a named query (TestQuery in the below screenshot) and you specify the query name given in the schema (getURL)

Query

How will we call the GraphQL API from outside AWS?
You can get the API Endpoint and API Key from the Settings screen in the API.

API Settings

With this data, lets call this API the old-fashioned way, with cURL. Replace APPSYNCAPIENDPOINT and APPSYNCAPIKEY in below command with actual values.

curl --location --globoff 'https://APPSYNCAPIENDPOINT?query=query%20TestQuery{%20getURL%20}' \
--header 'x-api-key: APPSYNCAPIKEY' \
--header 'Content-Type: application/json'
Enter fullscreen mode Exit fullscreen mode

In header we are passing the API Key and the GraphQL query is passed as a parameter query = query TestQuery{ getURL }. In above command, this part is url-encoded which converts spaces to %20.

Curl Command

A logical next step to this would be to use this API in AWS Amplify as the API backend for your fullstack app developed using Amplify. We will cover this in the next article.

Hope this was helpful!

Top comments (3)

Collapse
 
ortonomy profile image
πŸ…–πŸ…‘πŸ…”πŸ…–πŸ…žπŸ…‘πŸ…¨ πŸ…žπŸ…‘πŸ…£πŸ…žπŸ…

No. Don’t do it. AppSync is a trap and a very bad idea TM.

VTL templates are a dead end and are essentially instant tech debt. They’re written in a highly specific, ancient DSL that wasn’t written for the purpose they’re being used in AppSync. Hidden glue code that is alien and annoying to almost every developer/engineer who didn’t write JSP code 20-30 years ago.

But worst of all, and not written into the docs, is the way that AppSync operates as a service. It’s useful for downstream HTTP data sources, but if you use lambda data sources, it will execute a new lambda for every resolver. It makes it spectacularly easy to reach the lambda concurrency limit in AWS with even a small data set and a few nested resolvers. (Think only 50 rows of a list API)

Collapse
 
chrisdrobison profile image
Chris Robison

Please, for the love of all other devs and yourself, do NOT use AppSync. It is a terribly conceived service. Everything about it is a terrible experience and horrible to maintain. I’m working with a team who choose it. It went from bad to worse really quickly. Not only is VTL terrible to work with, debug and understand, if you step one foot outside what VTL can do, then you have to use lambda resolvers which are just as bad, especially when you have to start layering them together.

We are currently moving to a GraphQL server hosted in a container (.NET HotChocolate, but honestly any gql server in a container would be astronomically better than AppSync). Unsurprisingly, the devs can engineering things way faster because 1) they can understand it 2) they can actually run it locally to test it 3) they can attach a debugger. Seriously, do yourself a favor and forget that you ever heard about AppSync and go with a simple containerized GQL server. And if you want β€œserverless” put it in Fargate. Your grandchildren will love you for it.

Collapse
 
chrisdrobison profile image
Chris Robison

Take what you just did in this blog post and reproduce it in Apollo server and you will see just how asinine AppSync is in complexity.