Using AppSync Client from Lambda
Access your Amplify generated AppSync GraphlQL API from a lambda
Mon, 06 Jul 2020
It took me a while to figure out how to use the Amplify GraphQL client in a lambda so I can access my AppSync API. The main reason I wanted to use this is so I can invoke subscription updates to my frontend. If you’re interested in making signed https request, check out this tutorial.
Code
npm install aws-appsync es6-promise graphql-tag isomorphic-fetch
The env variables should all be provided by Amplify.
/* eslint-disable no-console */
require("es6-promise").polyfill();
require("isomorphic-fetch");
// eslint-disable-next-line import/no-extraneous-dependencies
const AWS = require("aws-sdk");
const AWSAppSyncClient = require("aws-appsync").default;
const { AUTH_TYPE } = require("aws-appsync");
const region = process.env.REGION;
AWS.config.update({
region
});
const appsyncUrl = process.env.API_RADLOOP_GRAPHQLAPIENDPOINTOUTPUT;
const gql = require("graphql-tag");
// graphql client. We define it outside of the lambda function in order for it to be reused during subsequent calls
let client;
// used to parse different types of query results to return only the item.
function parseResults(operationName, data) {
if (operationName.includes("List")) {
return data[`l${operationName.substring(1, operationName.length)}`];
}
if (operationName.includes("GetOrders")) {
return data[`g${operationName.substring(1, operationName.length)}`];
}
return data[operationName];
}
// initializes our graphql client
function initializeClient() {
client = new AWSAppSyncClient({
url: appsyncUrl,
region,
auth: {
type: AUTH_TYPE.AWS_IAM,
credentials: AWS.config.credentials
},
disableOffline: true
});
}
// generic mutation function. A way to quickly reuse mutation statements
async function executeMutation(mutation, operationName, variables) {
if (!client) {
initializeClient();
}
try {
const response = await client.mutate({
mutation: gql(mutation),
variables,
fetchPolicy: "network-only"
});
return parseResults(operationName, response.data);
} catch (err) {
console.log("Error while trying to mutate data");
throw JSON.stringify(err);
}
}
// generic query function. A way to quickly reuse query statements
async function executeQuery(query, operationName, variables) {
if (!client) {
initializeClient();
}
try {
const response = await client.query({
query: gql(query),
variables,
fetchPolicy: "network-only"
});
return parseResults(operationName, response.data);
} catch (err) {
console.log("Error while trying to fetch data");
throw JSON.stringify(err);
}
}
exports.handler = async event => {
console.log(event); // logging so you can see what gets passed when you invoke it
// updating a users firstName
await executeMutation(
`mutation updateUser($id: ID!) {
updateUser(id: $id) {
id
firstName
}
}`,
"updateOrder",
{
input: {
id: "1234",
firstName: "Bob"
}
}
);
// querying the user that we changed
const user = await executeQuery(
`query getUser($id: ID!) {
getUser(id: $id) {
id
fullName
firstName
lastName
}
}`,
"updateOrder",
{
id: "1234"
}
);
return user;
};
If you have trouble with permissions make sure the schema that you are accessing has lambda permissions as well as your lambda has permissions to access that schema.
Permissions for the schema
Example schema. This will allow cognito userpools as well as IAM(for lambda)
type User
@model
@auth(
rules: [
{
allow: private
provider: userPools
operations: [read, update, create]
}
{
allow: private
provider: iam
operations: [read, update, create, delete]
}
]
) {
id: ID!
firstName: String
}
Run an amplify push after
Permissions for the lambda
In your terminal at the root of your amplify directory:
-
amplify function update
- Select function that this code is in
- Let this function access other resources
- Select GraphQL/Appsync option
- Regardless of what this function does, give it Create, Update and Read. AWS is strange and your lambda requires these permissions to be able to access the AppSync API even if your lambda may not be using the those permissions.
-
amplify push