Sending GraphQL requests through AWS API Gateway using the Apollo client
At Merapar we frequently use GraphQL and for one particular project we have deployed it in AWS behind the Amazon API Gateway service. Security is managed using AWS Cognito federated identities, however in order to perform authenticated requests and take advantage of the Apollo client’s advanced features (such as caching, pre-fetching, subscriptions) we had to develop a new network interface for the Apollo GraphQL client. We have decided to open source the NPM, so that you can use it in your own projects.
The new network interface is available on Github and as an installable NPM:
- Github repository
- Installable NPM module
As we configured our AWS API Gateway to allow requests only to clients authenticated through via AWS Cognito federated identities, all requests towards the API Gateway had to be properly signed using the AWS Signature v4.
The main problem encountered was that the Apollo client did not allow the user to influence the actual request on the wire by, only to implement a middleware to tweak the HTTP request before Apollo itself performs the request. This prevented us from signing the request the AWS prescribed way: firstly, implementing this as a middleware was not sufficient, because at this stage the request’s payload was not available (the signature has to contain a checksum of the payload). Secondly, it prevented the use of the AWS generic SDK or the API Gateway custom SDK (that can be generated) to sign the request and send it directly towards the API Gateway.
In order to perform compliant requests towards the API Gateway, we had to develop an AWS network interface for the GraphQL Apollo client.
The idea was simple: extend the BaseNetworkInterface class of the Apollo client, overwriting it so requests are called using the API Gateway generated SDK instead of the fetch library. This SDK must be initiated with AWS credentials (accessKey, secretKey and session token) and can then perform requests towards the API Gateway as the authenticated user. It handles all the signature generations and appropriate headers insertion for all requests made to the API Gateway.
This new AWS network interface also allows the client to detect when the user session expires.
- Install the API Gateway network interface with : npm install apollo-client-aws-ni save
- Generate your AWS API Gateway custom SDK and download it. To do so, go to your API Gateway console and follow the steps described in the screenshot below. You can also use the AWS CLI tool to achieve this.
First, the following imports must be added :
Then, export a function that allows initialization of the AWS API GW generated SDK :
Here, AWS credentials have been stored in the browser local storage upon successful authentication. It is also important to specify the API Gateway AWS region.
Next, a wrapper for the generated SDK must be written. This allows the use of the network interface with a wide range of API Gateway configurations and use cases. This wrapper is also the place you should define what to do when the session expires.
In the last graphqlPost, you may need to swap the underlying apigClient.graphqlPost function with the one declared in your AWS SDK. By default the function name is the last part of your endpoint path concatened with the method. So if you access your graphql server through the API GW end point https://<my-api-gw>/<my-api-name>/graphql using the POST method, your SDK function name will be : graphqlPost
Finally, create the AwsApiGwNetworkInterface based on this wrapper and use it to create the Apollo Client.
Once those functions are defined and exported, you have to :
- pass the provideClient() function when you enable the (Angular) ApolloModule : ApolloModule.forRoot(provideClient);
- call the updateAwsApiGwClient() function into your authentication flow as soon as you get the AWS credentials.
You will then be able to initiate and use the Apollo client as usual.