graphql-request
graphql-request copied to clipboard
Add `requestFormatter` option to allow for signed request support for AWS AppSync / API Gateway
AWS API gateway & Appsync require each request to be signed via aws sig v4. This signing can't happen up front because the request body (aka query) must be also be included as part of the signing.
TLDR; This PR adds a generic requestFormatter option to allow me manipulation of the request, in this case signing the request, before it is sent.
Example usage:
import { GraphQLClient } from 'graphql-request'
// Async or sync function to get current AWS Cognito creds for request signing
const getCreds = async function() {
return {
accessKeyId: '123',
secretAccessKey: '456',
sessionToken: '789',
}
}
// Client with requestFormatter to manipulate payload right before fetch is called
const client = new GraphQLClient(ctx.url, {
/* Custom function for signing request */
requestFormatter: async function (payload) {
/* Get current user creds for API call */
const credentials = await getCreds()
const { accessKeyId, secretAccessKey, sessionToken } = credentials
if (!accessKeyId || !secretAccessKey) {
throw new Error('Not authenticated')
}
/* Sign the request with aws4 */
const signedRequest = aws4.sign(payload, {
accessKeyId,
secretAccessKey,
sessionToken
})
/* Return request signed request */
return signedRequest
}
})
// Now each request is properly signed
await client.request(`{ me { id } }`)
I've added tests along with this PR. Note: the aws4 is only used in the test as a dev dependency. Happy to remove it as a dev dep if ya'll want a different testing setup.
It's possible that is could also be solved by custom fetch proposed here: https://github.com/prisma-labs/graphql-request/pull/212
I'd prefer to provide a simple function instead of patching & providing my own fetch though 😃
@DavidWells you mentioned the use a custom fetch. It looks like aws4fetch might be perfect for this.
Also across the same topic, is there any update on this PR?