export const meta = { title: `Exporting AppSync operations to a Lambda layer for easy reuse`, description: `How to export your AppSync operations to a Lambda layer for easy reuse in your Lambda functions`, }; When you need to call your AppSync API from a Lambda function, you can export your AppSync operations generated by Amplify to a Lambda layer. This reduces the amount of duplicated code, and allows you to interact with the API from Lambda functions across multiple projects. ## Set up your layer Start by creating the layer that will contain your AppSync operations. ```sh $ amplify add function ? Select which capability you want to add: ❯ Lambda layer (shared code & resource used across functions) ? Provide a name for your Lambda layer: ? Choose the runtime that you want to use: ❯ NodeJS ✅ Lambda layer folders & files created: amplify/backend/function/appsyncOperations ``` In the `./amplify/backend/function/appsyncOperations/opt` folder add the following helper library. The library exports a `request` function that you can use to send queries or mutations to your AppSync API. You can specify an API KEY to include the `x-api-key` header in the request. Otherwise the request is signed using SigV4 and the invoked Lambda function's credentials. ```javascript // amplify/backend/function/appsyncOperations/opt/appSyncRequest.js const https = require('https') const AWS = require('aws-sdk') const urlParse = require('url').URL const region = process.env.REGION /** * * @param {Object} queryDetails the query, operationName, and variables * @param {String} appsyncUrl url of your AppSync API * @param {String} apiKey the api key to include in headers. if null, will sign with SigV4 */ exports.request = (queryDetails, appsyncUrl, apiKey) => { const req = new AWS.HttpRequest(appsyncUrl, region) const endpoint = new urlParse(appsyncUrl).hostname.toString() req.method = 'POST' req.path = '/graphql' req.headers.host = endpoint req.headers['Content-Type'] = 'application/json' req.body = JSON.stringify(queryDetails) if (apiKey) { req.headers['x-api-key'] = apiKey } else { const signer = new AWS.Signers.V4(req, 'appsync', true) signer.addAuthorization(AWS.config.credentials, AWS.util.date.getDate()) } return new Promise((resolve, reject) => { const httpRequest = https.request({ ...req, host: endpoint }, (result) => { let response = '' result.on('data', (chunk) => { response += chunk }) result.on('end', () => { response = JSON.parse(response) resolve(response) }) }) httpRequest.write(req.body) httpRequest.end() }) } ``` ## Generate compatible code for your layer Install the Babel dependencies to transpile the GraphQL javascript files generated by the Amplify codegen ```sh npm i --save-dev @babel/core @babel/cli @babel/preset-env ``` Add a Babel configuration file that specifies the compilation target. The configuration specifies that the only target is NodeJS 12. In `./babel.config.json`: ```json { "presets": [ [ "@babel/env", { "targets": { "node": "12" } } ] ] } ``` Add a command to the `scripts` in your `package.json` that updates your layer with the latest codegen: ```json { "scripts": { "updateAppsyncOperations": "amplify api gql-compile && amplify codegen && babel src/graphql --config-file ./babel.config.json -d ./amplify/backend/function//opt/graphql/" } } ``` Make sure to replace `` with the actual name of your Lambda layer. You can run this command after you've modified your schema to update the codegen and your layer: ```sh npm run updateAppsyncOperations ``` The `opt` directory of in your layer now looks like this: ```sh amplify/backend/function/appsyncOperations/opt ├── appsyncRequest.js └── graphql ├── mutations.js ├── queries.js └── subscriptions.js ``` You can push your changes to the cloud with `amplify push`. You can now assign the layer to Lambda functions to easily call your AppSync API. Here's how you can leverage it in a Lambda function that has IAM permissions to call your AppSync API. ```javascript const appsyncUrl = process.env.API_AMPLIFYLAYERGUIDE_GRAPHQLAPIENDPOINTOUTPUT const apiKey = process.env.API_AMPLIFYLAYERGUIDE_GRAPHQLAPIKEYOUTPUT const { request } = require('/opt/appsyncRequest') const { createTodo } = require('/opt/graphql/mutations') const { listTodos } = require('/opt/graphql/queries') exports.handler = async (event) => { try { // create a TODO with AWS_IAM auth var result = await request( { query: createTodo, variables: { input: { name: 'new todo', description: 'the first', }, }, }, appsyncUrl ) console.log('iam results:', result) // Now, retrieve all TODOs using API_KEY auth result = await request( { query: listTodos, operationName: 'ListTodos', }, appsyncUrl, apiKey ) console.log('api key results', result) } catch (error) { console.log(error) } } ```