How connect appsync and lambda
Tags: appsync, lambda, aws, serverless
Published: 2023-09-15 14:45:23

## Intro
The article is not intended for beginners and will not explain what GraphQL is or how to install Node.js or setup aws cli. Instead, it will focus on personal experience and info that hard to find. it's advisable to have  some free time, and a healthy sense of curiosity.


## What is [appsync](https://aws.amazon.com/ru/appsync/) ? 
This is a GraphQL server from AWS Amazon.

In AppSync, resolvers can be written in either JavaScript or can call an external lambda function and this lamda can handle all the logic.I prefer using Lambda because the runtime functionality for resolvers within AppSync is extremely limited. Example of limitations of js resolvers you can see by url https://docs.aws.amazon.com/appsync/latest/devguide/supported-features.html

Here some examples:
1. `apply`, `bind`, and `call` methods not are supported.
2. Function constructors are not supported.
3. Passing a function as an argument is not supported.
4. Recursive function calls are not supported.
5. Async processes are not supported, and promises are not supported.

IMHO Looks terrible. Immposible to write comlex code.

## AppSync drawbacks 
TLDR: You'll be solving problems that would never have arisen if you had chosen a different approach. For example

With lambda as resolver you have request flow like
1. A request comes from the user.
2. AppSync parses the request.
3. It transforms it into an object and sends it to the Lambda function over the network.
4. The Lambda function parses it, interacts with the database, computes the response, and sends it back to AppSync.
5. AppSync delivers the response to the user.

On the other hand with apollo:
1. A user request arrives.
2. Apollo parses it.
3. It handle with same  memory process , unlike AppSync, which does it over the network.
4. The resolver interacts with the database, performs calculations, etc.
5. And then returns this to the user.

Compared to a GraphQL server,
1. AppSync introduces an extra network request. 
2. Additionally, in the Lambda scenario, you would have to address the **N+1 query problem** at the Lambda level, without utilizing the Data Loader pattern.

Some other drawbacks
1. Also, AppSync does not support documentation in the GraphQL schema using triple quotes ("""), only hardcore "#" comments.
2. It has not supported documentation within enums for four years now! [Link to the issue](https://github.com/aws/aws-appsync-community/issues/55).



## How to connect  lambda и appsync ?
I prefer using the Serverless Framework and its associated plugin serverless-appsync-plugin.

Attention, the instructions for the serverless-appsync-plugin on the website https://www.serverless.com/plugins/serverless-appsync-plugin are outdated. **Don't use it**. Looks at real doc on https://github.com/sid88in/serverless-appsync-plugin/blob/master/README.md.

## Quckstart
clone my template repo
```shell
git clone https://github.com/R11baka/appsynctemplate && cd appsynctemplate
```
After that run
```shell
npm install
```
Useful commands that appear after installing the serverless-appsync-plugin.

```shell!
npx sls appsync validate-schema
```
Schema validation. It partially ensures that your schema is valid. It won't save you if you have comments within an enum.

## What's going on ?
The heart of application and most tricky, from my point of view is serverless.yaml file. Let's try to see

```yaml=
service: appsync-demo  
frameworkVersion: "3"
configValidationMode: "warn"

provider:
  name: aws
  runtime: nodejs18.x
  stage: ${opt:stage, self:custom.defaultStage}
  region: us-west-1
  versionFunctions: true
  logRetentionInDays: 90
  environment:
    AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1

plugins:
  - serverless-appsync-plugin # attach appsync-plugin to serverless
custom:
  defaultStage: dev

appSync:
  name: appsync-demo-${self:provider.stage}
  schema: 'schema.graphql' # path relative to serverless.yaml file
  authentication:
    type: 'API_KEY' # type of auth. Also can be cognito, and custom AWS_LAMBDA
  apiKeys:
    - name: apiKey
      description: dev API key
      expiresAfter: 1M
  dataSources:
    appsyncLambdaDataSource:
      type: AWS_LAMBDA
      name: appsyncLambda
      config:
        functionName: appsyncLambda # name of lambda
  resolvers:
    query:
      type: Query # Hello resolver
      field: hello
      dataSource: appsyncLambdaDataSource 
      kind: UNIT

functions:
  appsyncLambda:
    name: appsyncLambda-${self:provider.stage}
    description: Lambda resolver which accept events from appsync
    timeout: 15
    handler: src/index.handler # points to main entry point
```

So tricky part is definition datasource, resolver, lambdaname.
1. Resolver on 36 line points to datasource with name appsyncLambdaDataSource.
2. appsyncLambdaDataSource point on lambda with name appsyncLambda, which defined on 43 line

### How to deploy ?
Deploy to dev 
```shell!
npm sls deploy --stage=dev --verbose
```
Deploy to live
```shell
npx sls deploy --stage=live --verbose
```

After deploy you will see in console output something like 
```shell=
Stack Outputs:
  AppsyncLambdaLambdaFunctionQualifiedArn: arn:aws:lambda:us-west-1:7412810041:function:appsyncLambda-dev:5
  ServerlessDeploymentBucketName: appsync-demo-dev-serverlessdeploymentbucket-u48ln3fiu
appsync endpoints:
  graphql: https://s6ghsxmtbnfaxperetsottu.appsync-api.us-west-1.amazonaws.com/graphql
  realtime: wss://s6ghsxmtbnfaxpp2u4metsottu.appsync-realtime-api.us-west-1.amazonaws.com/graphql
appsync api keys:
  da2-gihxmtd34bf2ncouh2nseu (dev API key)
```
Go to the https://studio.apollographql.com/sandbox/explorer?referrer=docs-nav, paste graphqlurl in top. 
And add header x-api-key: da2-gihxmtd34bf2ncouh2nseu to the headers sections. You are ready to request appsync