Giter Site home page Giter Site logo

serverless-appsync / serverless-appsync-simulator Goto Github PK

View Code? Open in Web Editor NEW
127.0 8.0 69.0 1.89 MB

A simple wrapper around Amplify AppSync Simulator to test serverless AppSync Apis

License: MIT License

JavaScript 100.00%
appsync aws-appsync serverless graphql serverless-plugin

serverless-appsync-simulator's Introduction

semantic-release Release All Contributors

This serverless plugin is a wrapper for amplify-appsync-simulator made for testing AppSync APIs built with serverless-appsync-plugin.

Requires

Install

npm install serverless-appsync-simulator
# or
yarn add serverless-appsync-simulator

Usage

This plugin relies on your serverless yml file and on the serverless-offline plugin.

plugins:
  - serverless-dynamodb-local # only if you need dynamodb resolvers and you don't have an external dynamodb
  - serverless-appsync-simulator
  - serverless-offline

Note: Order is important serverless-appsync-simulator must go before serverless-offline

To start the simulator, run the following command:

sls offline start

You should see in the logs something like:

...
Serverless: AppSync endpoint: http://localhost:20002/graphql
Serverless: GraphiQl: http://localhost:20002
...

Configuration

Put options under custom.appsync-simulator in your serverless.yml file

option default description
apiKey 0123456789 When using API_KEY as authentication type, the key to authenticate to the endpoint.
port 20002 AppSync operations port; if using multiple APIs, the value of this option will be used as a starting point, and each other API will have a port of lastPort + 10 (e.g. 20002, 20012, 20022, etc.)
wsPort 20003 AppSync subscriptions port; if using multiple APIs, the value of this option will be used as a starting point, and each other API will have a port of lastPort + 10 (e.g. 20003, 20013, 20023, etc.)
location . (base directory) Location of the lambda functions handlers.
refMap {} A mapping of resource resolutions for the Ref function
getAttMap {} A mapping of resource resolutions for the GetAtt function
importValueMap {} A mapping of resource resolutions for the ImportValue function
functions {} A mapping of external functions for providing invoke url for external fucntions
dynamoDb.endpoint http://localhost:8000 Dynamodb endpoint. Specify it if you're not using serverless-dynamodb-local. Otherwise, port is taken from dynamodb-local conf
dynamoDb.region localhost Dynamodb region. Specify it if you're connecting to a remote Dynamodb intance.
dynamoDb.accessKeyId DEFAULT_ACCESS_KEY AWS Access Key ID to access DynamoDB
dynamoDb.secretAccessKey DEFAULT_SECRET AWS Secret Key to access DynamoDB
dynamoDb.sessionToken DEFAULT_ACCESS_TOKEEN AWS Session Token to access DynamoDB, only if you have temporary security credentials configured on AWS
dynamoDb.* You can add every configuration accepted by DynamoDB SDK
rds.dbName Name of the database
rds.dbHost Database host
rds.dbDialect Database dialect. Possible values (mysql/postgres)
rds.dbUsername Database username
rds.dbPassword Database password
rds.dbPort Database port
openSearch.useSignature false Enable signing requests to OpenSearch. The preference for credentials is config > environment variables > local credential file.
openSearch.region OpenSearch region. Specify it if you're connecting to a remote OpenSearch intance.
openSearch.accessKeyId AWS Access Key ID to access OpenSearch
openSearch.secretAccessKey AWS Secret Key to access OpenSearch
watch - *.graphql
- *.vtl
Array of glob patterns to watch for hot-reloading.

Example:

custom:
  appsync-simulator:
    location: '.webpack/service' # use webpack build directory
    dynamoDb:
      endpoint: 'http://my-custom-dynamo:8000'

Hot-reloading

By default, the simulator will hot-relad when changes to *.graphql or *.vtl files are detected. Changes to *.yml files are not supported (yet? - this is a Serverless Framework limitation). You will need to restart the simulator each time you change yml files.

Hot-reloading relies on watchman. Make sure it is installed on your system.

You can change the files being watched with the watch option, which is then passed to watchman as the match expression.

e.g.

custom:
  appsync-simulator:
    watch:
      - ["match", "handlers/**/*.vtl", "wholename"] # => array is interpreted as the literal match expression
      - "*.graphql"                                 # => string like this is equivalent to `["match", "*.graphql"]`

Or you can opt-out by leaving an empty array or set the option to false

Note: Functions should not require hot-reloading, unless you are using a transpiler or a bundler (such as webpack, babel or typescript), un which case you should delegate hot-reloading to that instead.

Resource CloudFormation functions resolution

This plugin supports some resources resolution from the Ref, Fn::GetAtt and Fn::ImportValue functions in your yaml file. It also supports some other Cfn functions such as Fn::Join, Fb::Sub, etc.

Note: Under the hood, this features relies on the cfn-resolver-lib package. For more info on supported cfn functions, refer to the documentation

Basic usage

You can reference resources in your functions' environment variables (that will be accessible from your lambda functions) or datasource definitions. The plugin will automatically resolve them for you.

provider:
  environment:
    BUCKET_NAME:
      Ref: MyBucket # resolves to `my-bucket-name`

resources:
  Resources:
    MyDbTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: myTable
      ...
    MyBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: my-bucket-name
    ...

# in your appsync config
dataSources:
  - type: AMAZON_DYNAMODB
    name: dynamosource
    config:
      tableName:
        Ref: MyDbTable # resolves to `myTable`

Override (or mock) values

Sometimes, some references cannot be resolved, as they come from an Output from Cloudformation; or you might want to use mocked values in your local environment.

In those cases, you can define (or override) those values using the refMap, getAttMap and importValueMap options.

  • refMap takes a mapping of resource name to value pairs
  • getAttMap takes a mapping of resource name to attribute/values pairs
  • importValueMap takes a mapping of import name to values pairs

Example:

custom:
  appsync-simulator:
    refMap:
      # Override `MyDbTable` resolution from the previous example.
      MyDbTable: 'mock-myTable'
    getAttMap:
      # define ElasticSearchInstance DomainName
      ElasticSearchInstance:
        DomainEndpoint: 'localhost:9200'
    importValueMap:
      other-service-api-url: 'https://other.api.url.com/graphql'

# in your appsync config
dataSources:
  - type: AMAZON_ELASTICSEARCH
    name: elasticsource
    config:
      # endpoint resolves as 'http://localhost:9200'
      endpoint:
        Fn::Join:
          - ''
          - - https://
            - Fn::GetAtt:
                - ElasticSearchInstance
                - DomainEndpoint

Key-value mock notation

In some special cases you will need to use key-value mock nottation. Good example can be case when you need to include serverless stage value (${self:provider.stage}) in the import name.

This notation can be used with all mocks - refMap, getAttMap and importValueMap

provider:
  environment:
    FINISH_ACTIVITY_FUNCTION_ARN:
      Fn::ImportValue: other-service-api-${self:provider.stage}-url

custom:
  serverless-appsync-simulator:
    importValueMap:
      - key: other-service-api-${self:provider.stage}-url
        value: 'https://other.api.url.com/graphql'

Limitations

This plugin only tries to resolve the following parts of the yml tree:

  • provider.environment
  • functions[*].environment
  • custom.appSync

If you have the need of resolving others, feel free to open an issue and explain your use case.

For now, the supported resources to be automatically resovled by Ref: are:

  • DynamoDb tables
  • S3 Buckets

Feel free to open a PR or an issue to extend them as well.

External functions

When a function is not defined withing the current serverless file you can still call it by providing an invoke url which should point to a REST method. Make sure you specify "get" or "post" for the method. Default is "get", but you probably want "post".

custom:
  appsync-simulator:
    functions:
      addUser:
        url: http://localhost:3016/2015-03-31/functions/addUser/invocations
        method: post
      addPost:
        url: https://jsonplaceholder.typicode.com/posts
        method: post

Supported Resolver types

This plugin supports resolvers implemented by amplify-appsync-simulator, as well as custom resolvers.

From Aws Amplify:

  • NONE
  • AWS_LAMBDA
  • AMAZON_DYNAMODB
  • PIPELINE

Implemented by this plugin

  • AMAZON_ELASTICSEARCH
  • HTTP
  • RELATIONAL_DATABASE

Relational Database

Sample VTL for a create mutation

#set( $cols = [] )
#set( $vals = [] )
#foreach( $entry in $ctx.args.input.keySet() )
  #set( $regex = "([a-z])([A-Z]+)")
  #set( $replacement = "$1_$2")
  #set( $toSnake = $entry.replaceAll($regex, $replacement).toLowerCase() )
  #set( $discard = $cols.add("$toSnake") )
  #if( $util.isBoolean($ctx.args.input[$entry]) )
      #if( $ctx.args.input[$entry] )
        #set( $discard = $vals.add("1") )
      #else
        #set( $discard = $vals.add("0") )
      #end
  #else
      #set( $discard = $vals.add("'$ctx.args.input[$entry]'") )
  #end
#end
#set( $valStr = $vals.toString().replace("[","(").replace("]",")") )
#set( $colStr = $cols.toString().replace("[","(").replace("]",")") )
#if ( $valStr.substring(0, 1) != '(' )
  #set( $valStr = "($valStr)" )
#end
#if ( $colStr.substring(0, 1) != '(' )
  #set( $colStr = "($colStr)" )
#end
{
  "version": "2018-05-29",
  "statements":   ["INSERT INTO <name-of-table> $colStr VALUES $valStr", "SELECT * FROM    <name-of-table> ORDER BY id DESC LIMIT 1"]
}

Sample VTL for an update mutation

#set( $update = "" )
#set( $equals = "=" )
#foreach( $entry in $ctx.args.input.keySet() )
  #set( $cur = $ctx.args.input[$entry] )
  #set( $regex = "([a-z])([A-Z]+)")
  #set( $replacement = "$1_$2")
  #set( $toSnake = $entry.replaceAll($regex, $replacement).toLowerCase() )
  #if( $util.isBoolean($cur) )
      #if( $cur )
        #set ( $cur = "1" )
      #else
        #set ( $cur = "0" )
      #end
  #end
  #if ( $util.isNullOrEmpty($update) )
      #set($update = "$toSnake$equals'$cur'" )
  #else
      #set($update = "$update,$toSnake$equals'$cur'" )
  #end
#end
{
  "version": "2018-05-29",
  "statements":   ["UPDATE <name-of-table> SET $update WHERE id=$ctx.args.input.id", "SELECT * FROM <name-of-table> WHERE id=$ctx.args.input.id"]
}

Sample resolver for delete mutation

{
  "version": "2018-05-29",
  "statements":   ["UPDATE <name-of-table> set deleted_at=NOW() WHERE id=$ctx.args.id", "SELECT * FROM <name-of-table> WHERE id=$ctx.args.id"]
}

Sample mutation response VTL with support for handling AWSDateTime

#set ( $index = -1)
#set ( $result = $util.parseJson($ctx.result) )
#set ( $meta = $result.sqlStatementResults[1].columnMetadata)
#foreach ($column in $meta)
    #set ($index = $index + 1)
    #if ( $column["typeName"] == "timestamptz" )
        #set ($time = $result["sqlStatementResults"][1]["records"][0][$index]["stringValue"] )
        #set ( $nowEpochMillis = $util.time.parseFormattedToEpochMilliSeconds("$time.substring(0,19)+0000", "yyyy-MM-dd HH:mm:ssZ") )
        #set ( $isoDateTime = $util.time.epochMilliSecondsToISO8601($nowEpochMillis) )
        $util.qr( $result["sqlStatementResults"][1]["records"][0][$index].put("stringValue", "$isoDateTime") )
    #end
#end
#set ( $res = $util.parseJson($util.rds.toJsonString($util.toJson($result)))[1][0] )
#set ( $response = {} )
#foreach($mapKey in $res.keySet())
    #set ( $s = $mapKey.split("_") )
    #set ( $camelCase="" )
    #set ( $isFirst=true )
    #foreach($entry in $s)
        #if ( $isFirst )
          #set ( $first = $entry.substring(0,1) )
        #else
          #set ( $first = $entry.substring(0,1).toUpperCase() )
        #end
        #set ( $isFirst=false )
        #set ( $stringLength = $entry.length() )
        #set ( $remaining = $entry.substring(1, $stringLength) )
        #set ( $camelCase = "$camelCase$first$remaining" )
    #end
    $util.qr( $response.put("$camelCase", $res[$mapKey]) )
#end
$utils.toJson($response)

Using Variable Map

Variable map support is limited and does not differentiate numbers and strings data types, please inject them directly if needed.

Will be escaped properly: null, true, and false values.

{
  "version": "2018-05-29",
  "statements":   [
    "UPDATE <name-of-table> set deleted_at=NOW() WHERE id=:ID",
    "SELECT * FROM <name-of-table> WHERE id=:ID and unix_timestamp > $ctx.args.newerThan"
  ],
  variableMap: {
    ":ID": $ctx.args.id,
##    ":TIMESTAMP": $ctx.args.newerThan -- This will be handled as a string!!!
  }
}

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Benoît Bouré

💻

Filip Pýrek

💻

Marco Reni

💻

Egor Dmitriev

💻

Steffen Schwark

💻

Nicky Moelholm

💻

g-awa

💻

Lee Mulvey

💻

Jimmy Hurrah

💻

Abdala

🤔

Alexandru Savin

📖

Scale93

💻 📖

Ryo Yamada

💻 📖

h-kishi

💻

louislatreille

💻

Aleksa Cukovic

💻

Sean van Mulligen

💻

Diego Rodrigues Ferreira

💻

Mohammed Ali Chherawalla

💻

AdrianTodt

💻

This project follows the all-contributors specification. Contributions of any kind welcome!

serverless-appsync-simulator's People

Contributors

aleksac avatar alexandrusavin avatar alichherawalla avatar allcontributors[bot] avatar alvaroseparovich avatar bboure avatar daisuke-awaji avatar dependabot[bot] avatar diegofleitas avatar egordm avatar filippyrek avatar generalman025 avatar h-kishi avatar iamdavidmartin avatar jimmyhurrah avatar katesclau avatar liooo avatar lkhari avatar lmulveycm avatar louislatreille avatar marcoreni avatar moelholm avatar scale93 avatar seanvm avatar semantic-release-bot avatar stschwark avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

serverless-appsync-simulator's Issues

TypeError: Cannot read property 'path' of undefined (v0.14.0 - absolute paths computation on Windows)

Describe the bug

This PR breaks the plugin on Windows because absolute schema paths does not get computed properly.

sls offline start relevant log

# Note: Variables logs of getAppSyncConfig.js
getAppSyncConfig / schemaPaths [ 'graphql/schema.graphql' ]
getAppSyncConfig / basePath D:\_dev\_projects\redacted
globFilePaths / filePaths [ 'graphql/schema.graphql' ]
globFilePaths / basePath D:\_dev\_projects\redacted
globFilePaths / paths []
getAppSyncConfig / schemas []

 Type Error ----------------------------------------------

  TypeError: Cannot read property 'path' of undefined
      at getAppSyncConfig (D:\_dev\_projects\redacted\node_modules\serverless-appsync-simulator\lib\getAppSyncConfig.js:254:38)
      at ServerlessAppSyncSimulator.initServer (D:\_dev\_projects\redacted\node_modules\serverless-appsync-simulator\lib\index.js:85:50)
      at Client.<anonymous> (D:\_dev\_projects\redacted\node_modules\serverless-appsync-simulator\lib\index.js:147:14)
      at Client.emit (events.js:210:5)
      at Client.EventEmitter.emit (domain.js:475:20)
      at BunserBuf.<anonymous> (D:\_dev\_projects\redacted\node_modules\serverless-appsync-simulator\node_modules\fb-watchman\index.js:90:14)
      at BunserBuf.emit (events.js:210:5)
      at BunserBuf.EventEmitter.emit (domain.js:475:20)
      at BunserBuf.process (D:\_dev\_projects\redacted\node_modules\serverless-appsync-simulator\node_modules\bser\index.js:292:10)
      at D:\_dev\_projects\redacted\node_modules\serverless-appsync-simulator\node_modules\bser\index.js:247:12
      at processTicksAndRejections (internal/process/task_queues.js:75:11)

     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com

  Your Environment Information ---------------------------
     Operating System:          win32
     Node Version:              12.14.0
     Framework Version:         2.35.0 (local)
     Plugin Version:            4.5.3
     SDK Version:               4.2.2
     Components Version:        3.8.3

To Reproduce
Run v0.15.0 on Windows

Expected behavior
Absolute schema paths should get computed properly

Additional context

A schema with a Lambda Resolver in GraphiQL had an empty response error.

Describe the bug
I tried to start it offline with serverless-appsync-simulator by writing serverless.yml as follows.

# serverless.yml
custom:
  dynamodb:
    start:
      seed: true
      migrate: true
      inMemory: true
    stages:
      - dev
    seed:
      dev:
        sources:
          - table: ${self:service.name}_${self:provider.stage}_User
            sources: [./test/migrations/users.json]
          - table: ${self:service.name}_${self:provider.stage}_Channel
            sources: [./test/migrations/channels.json]
#...
  appSync:
    dataSources:
      - type: AWS_LAMBDA
        name: GetUserByName
        description: "Function to get user information based on a user's name"
        config:
          functionName: GetUserByName
          iamRoleStatements:
            - Effect: "Allow"
              Action:
                - "lambda:invokeFunction"
              Resource:
                - "*"
#...
    mappingTemplates:
      - dataSource: GetUserByName
        type: Query
        field: getUserByName
        request: functions.request.vtl
        response: functions.response.vtl
#...
    functionConfigurations:
      - dataSource: GetUserByName
        name: GetUserByName
        request: functions.request.vtl
        response: functions.response.vtl
#...
functions:
  GetUserByName:
    role: ServerlessRoleDev
    handler: AppSync.GetUserByName
// handler.ts
// ...
interface GetUserByNameInput {
  username: string;
}
export const GetUserByName: LambdaResolver = async (
  event: GetUserByNameInput
) => {
  console.log(event);
  const username = event.username;
  const user = await entityManager.getUserByName(username);

  return { ...event, ...user };
};
// ...

I have verified that the IS_OFFLINE=1 sls offline start can be started successfully, and the aws lambda invoke command can be used.

aws lambda invoke /dev/null \
    --endpoint-url http://localhost:3002 \
    --function-name live-service-dev-GetUserByName \
    --payload '{ "username": "kadinche3" }' --cli-binary-format raw-in-base64-out
{
    "StatusCode": 200
}

{ username: 'tes' }
{"data":{"listUsers":{"items":[{"id":"8d7105ff-fd2a-0d77-d817-cb032e7626b3","username":"tes","email":"[email protected]","type":"Admin","channel_ids":["eedc2c40-f714-cb81-29a6-6c8abae660c3"],"created_at":"12345","updated_at":"12345","__typename":"User"}],"nextToken":null,"__typename":"UserConnection"}},"loading":false,"networkStatus":7,"stale":false}
offline: (λ: GetUserByName) RequestId: ckga7oh4j00007ujl92u4aprq  Duration: 962.32 ms  Billed Duration: 1000 ms

However, when trying to execute the same command with GraphiQL, the response was not returned. Also, when I checked the terminal, there was no output of access from GraphiQL. (What I find most suspicious right now is that it doesn't seem to be able to run Lambda Resolver.)

スクリーンショット 2020-10-15 12 03 24

I know it looks like a timeout error as well, could you please tell what might be causing it?
Please let me know if there is any other information that might be helpful or an item I should verify. 🙏 🙇

To Reproduce
I've described the procedure in "Describe the bug" so I'll describe my environment below.

  • Serverless
    • Framework Core: 2.7.0 (local)
    • Plugin: 4.1.0
    • SDK: 2.3.2
    • Components: 3.2.1
  • serverless-offline 6.8.0
  • serverless-appsync-plugin 1.4.0
  • serverless-appsync-simulator 0.7.0
  • amplify-appsync-simulator 1.14.0

Expected behavior
I thought the result would be like aws lambda invoke when I used the schema with the Lambda Resolver in GraphiQL.

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context

  • All of the DynamoDB resolvers worked successfully in GraphiQL as well. (ex. getUser, listUsers, deleteUser, createUser, etc.)

スクリーンショット 2020-10-15 13 25 07

スクリーンショット 2020-10-15 13 25 33

  • I have done sls deploy and verified in the AWS Console, and the function with Lambda Resolver has been successfully executed.

スクリーンショット 2020-10-15 12 52 51

  • I have seed data in the user table, but the number of seed data in the user table is 5, which is not a lot.

Anyway, I'm very grateful for your plugins, I use them almost every time I develop with Serverless Framework. 🛠️ I've been investigating this case by myself, but I wanted your help and created an issue. 📝 🙇

Simulator Halts Prematurely During Integration test

Describe the bug
I've been working on getting the Simulator up and running for some Integration testing w/Jest. I've roughly been following instructions found in a pretty neat little article about doing this using serverless-offline. The goal is to run some Jest tests in my CI/CD pipeline, using node-fetch to automate posting queries and mutations against this simulator prior to deploy.

I can successfully start the simulator in my Jest beforeAll() and it will run the test all the way through with node-fetch simulating the client, then shut down the simulator when it's done using Jest's afterAll().

However.....

I can run the same test, change no code, and it will succeed and fail randomly. This behavior appears to be due a race condition where sometimes the simulator shuts down before the test can run.

To Reproduce
I'm working on a more concise reproducible set of code. There's way too much noise in the current code to be useful here yet. I'll update this ticket once that happens but wanted to post anyway in case there is an obvious quick answer I am just not seeing.

Expected behavior
Success with Jest integration tests should be repeatable.

Screenshots
This is the console output around the simulator shutting down.

offline: Function names exposed for local invocation by aws-sdk:
[offline] Lambda Invocation Routes (for AWS SDK or AWS CLI):
[offline] Lambda Async Invocation Routes (for AWS SDK or AWS CLI):
AppSync Simulator: Halting AppSync Simulator

Then the jest test fails with error (sometimes):
FetchError: request to http://192.168.1.39:20002/graphql failed, reason: connect ECONNREFUSED 192.168.1.39:20002

Additional context
Commenting out this plugin's binding to the 'before:offline:start:end' hook makes my problem go away entirely and the tests runs correctly every time without fail.

TypeError: Cannot read property 'evaluate' of undefined

Describe the bug
AppSync Simulator: TypeError: Cannot read property 'evaluate' of undefined.

image
Iam learning a serverless framework right now so I used a start template and added appsync-simulator on it , thank you for your time guys.

This is my serverless.yml file

service:
  name: ${self:custom.serviceName}-backend


plugins:
  - serverless-webpack
  - serverless-appsync-plugin
  - serverless-pseudo-parameters
  - serverless-plugin-aws-alerts
  - serverless-deployment-bucket
  - serverless-appsync-simulator
  - serverless-offline

# The `provider` block defines where your service will be deployed
provider:
  name: aws
  runtime: nodejs12.x
  region: us-east-1
  stage: dev
  memorySize: ${self:custom.env.lambdaMemorySize.${self:provider.stage}, self:custom.env.lambdaMemorySize.default} # optional, in MB, default is 1024
  timeout: ${self:custom.env.lambdaTimeout.${self:provider.stage}, self:custom.env.lambdaTimeout.default} # optional, in seconds, default is 6
  versionFunctions: false # optional, default is true
  logRetentionInDays: 14 # Set the default RetentionInDays for a CloudWatch LogGroup
  deploymentBucket:
    name: ${self:custom.serviceName}-${self:provider.stage}-deploys
    serverSideEncryption: AES256
  apiGateway:
    binaryMediaTypes:
      - "*/*"

package:
  individually: true
  excludeDevDependencies: true
  
custom:
  appsync-simulator: # appsync-offline configuration
    location: ".webpack/service/src" # use webpack build directory
  env:
    appSyncLogLevel:
      dev: ERROR
      stage: ERROR
      prod: ERROR
      default: ALL
    # for some reason pseudo-parameter #{AWS::AccountId} does not work ${file(../serverless.yml):custom.name}
    lambdaMemorySize:
      dev: 256
      stage: 256
      prod: 512
      default: 128
    lambdaTimeout:
      dev: 6
      stage: 6
      prod: 8
      default: 4
    accountId:
      prod: xxxxxxxxxxxxx # TODO: change xxxxxxxxxxxxx to your prod accountId
      default: xxxxxxxxxxxxx # TODO: change xxxxxxxxxxxxx to your accountId
  region: "${self:provider.region}"
  accountId: ${self:custom.env.accountId.${self:provider.stage}, self:custom.env.accountId.default}
  serviceName: "xxx" # TODO: change xxx to your name
  name: "${self:service.name}-${self:provider.stage}"
  nameU: "${self:custom.serviceName}_backend_${self:provider.stage}"
  appSync: # appsync plugin configuration
    name: "smart-business-appsync"
    authenticationType: API_KEY
    serviceRole: "AppSyncServiceRole"
    dataSources: ${file(api/appsync/datasources.yml)}
    mappingTemplates: ${file(api/appsync/mappings.yml)}
   webpack:
     includeModules:
       forceInclude:
         - source-map-support
       forceExclude:
        - aws-sdk


functions: ${file(resources/lambda-functions.yml)}

# Create resources with separate CloudFormation templates
resources: ${file(resources/resources.yml)}

Plugin crashes with a VPC and GetAZs in the stack (Index 0 is out of bound)

Describe the bug
appsync-simulator does not succeed to launch if a VPC with GetAZs attributes is present in the stack.
The error message is Index *n* is out of bound.

To Reproduce
Here is a repro repo: https://github.com/somq/appsync-out-of-bound-issue

Expected behavior
cfn-resolver should be able to parseGetAZs & appsync-simulator should run and output the graphql URLs.

Additional context
I've tried to debug but it is not clear to me where does the issue come from.
In Index *n* is out of bound. n corresponds to the index of the AZ array, but cfn-resolvers fails to map the region to its AZ because currentRegion is undefined.

Any help would be appreciated at this point.

API key is readonly in Amplify GraphQL UI

Describe the bug
I was trying to change the API key in the Amplify GraphQL UI, but the input is readonly.
So then I need to set as API key, the one from Amplify GraphQL UI

appsync-simulator:
    apiKey: da2-fakeApiId123456

To Reproduce
Click on "Update Auth", then try changing the value of the "ApiKey" input.

Expected behavior
Hotfix: use the Amplify GraphQL UI key as the default one
Proper fix: fix it in Amplify GraphQL UI

Screenshots
image

AppSync Simulator just hangs

Describe the bug
I tried to execute a lambda but it just hangs. Calling the lambda directly using the AWS CLI works, though. No logs are shown, even with export SLS_DEBUG true and --verbose

To Reproduce
The following plugins are used:

plugins:
  - serverless-appsync-plugin
  - serverless-pseudo-parameters
  - serverless-plugin-warmup
  - serverless-appsync-simulator
  - serverless-offline

Our AppSync uses Cognito User Pools + API Key as authentication methods, but I configured both the simulator as well as serverless-offline to use the same API key.

Expected behavior
I expected it to show a log or something, instead of just hanging.

Screenshots
image
Here's the screenshot of it hanging on GraphiQL.

Additional context
N/A

0.19 Variable Map injection broken by replaceAll

Describe the bug
replaceAll is not a supported function. We need to fall back to replace with RegExp.

TypeError: statmnt.replaceAll is not a function
    at .../node_modules/serverless-appsync-simulator/lib/data-loaders/RelationalDataLoader.js:129:20

To Reproduce
Create a Query on and RDS Data source with variableMap

{
  "version": "2018-05-29",
  "statements": [
    "SELECT :VALUE"
  ],
  "variableMap": {
      ":VALUE": "$ctx.args.value"
  }
}

Run it and watch it break.

Expected behavior
The query returns the value in the response $ctx.result

ApiKey not working

Describe the bug
Affter setting the apikey under the cunstom configuration of appsync-simulator, i am sitll getting "UnauthorizedException: Invalid API key"

{"statusCode":404,"error":"Not Found","message":"Not Found"}

Describe the bug
{"statusCode":404,"error":"Not Found","message":"Not Found"}
http://localhost:3002

To Reproduce
$serverless offline
offline: Starting Offline: dev/us-east-1.
offline: Offline [http for lambda] listening on http://localhost:3002
offline: Function names exposed for local invocation by aws-sdk:

Expected behavior
Expecting to not get error

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
Add any other context about the problem here.

Default response vtl behvior not supported

Describe the bug
Per AWS Lambda Resovler docs:

Direct Lambda response mapping template

When the response mapping template is not provided, AWS AppSync will do one of two things upon receiving your Lambda > function's response. If you did not provide a request mapping template, or if you provided a request mapping template with > the version "2018-05-29", the response logic functions equivalent to the following response mapping template:

#if($ctx.error)
     $util.error($ctx.error.message, $ctx.error.type, $ctx.result)
 #end
 $util.toJson($ctx.result)

**NOTE: I had to update the above snippet to be the following to work correctly:

#if($ctx.error)
     $util.error($ctx.error.message, $ctx.error.type, $ctx.result)
 #else
   $util.toJson($ctx.result)
 #end

Currently, errors from underlying APIs are not bubbled up to the GraphQL response; rather you will see a message like this (if a resource is not found, for example):

{
    "data": {
        "program": null
    },
    "errors": [
        {
            "message": "Cannot return null for non-nullable field Program.id.",
            "locations": [
                {
                    "line": 3,
                    "column": 13
                }
            ],
            "path": [
                "program",
                "id"
            ]
        }
    ]
}

To Reproduce
Make a request for a resource with an ID that does not exist that should result in a 404 Not Found from an underlying API. The message from the API will not be shown in your response. For example:

query {
          foo(id: "SomeFakeID") {
            id
          }
        }

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
Screen Shot 2021-10-01 at 6 51 05 AM

Additional context
See also, Serverless docs for serverless-app-sync-plugin

Simulating Subscriptions

@bboure I really appreciate your efforts in contributing to serverless-appsync-plugin and creating this awesome serverless-appsync-simulator plugin.

I'm facing problem testing subscriptions, I'm assuming subscription endpoint is ws://${IP_ADRESS}:20003/graphql

when I subscribe, a message "listening" continues to show up but on mutation, nothing would happen with a subscription(no data is received).

I'm using graphql explorer to test subscription.

(for now we don't handle number )Return error when call API using number variable

Describe the bug
I got that error when I called API from the postman

#set( $expValues = {} )
$!{expValues.put(":price", {"N" : 0})}
#set( $expression = "price = :price " )
The error appears because the price is not a srtring

But it is working correctly using AWS Appsync console

"message": "Unable to convert {mapper=function map(value) {\n if (value instanceof map_1.JavaMap)\n return value;\n if (value instanceof array_1.JavaArray)\n return value;\n if (Array.isArray(value)) {\n return new array_1.JavaArray(value.map(function (x) { return map(x); }), map);\n }\n if (lodash_1.isPlainObject(value)) {\n return map_1.createMapProxy(new map_1.JavaMap(Object.entries(value).reduce(function (sum, _a) {\n var _b;\n var k = _a[0], v = _a[1];\n return __assign(__assign({}, sum), (_b = {}, _b[k] = map(v), _b));\n }, {}), map));\n }\n // eslint-disable-next-line\n if (typeof value === 'string' && !(value instanceof string_1.JavaString)) {\n // eslint-disable-next-line\n return new string_1.JavaString(value);\n }\n // for now we don't handle number.\n return value;\n}, map=[object Map]}\n\n{\n "version" : "2017-02-28",\n "operation" : "Query",\n "index": "status-rating-index"\n ,"query" : {\n "expression" : "#status = :status",\n "expressionNames": { "#status": "status" },\n "expressionValues" : {\n ":status" : {"S":"APPROVED"}\n }\n }\n ,"scanIndexForward" : false\n ,"filter": {\n "expression" : "price = :price",\n "expressionValues" : {":price":{"N":0}}\n }\n } to class com.amazonaws.deepdish.transform.model.lambda.LambdaVersionedConfig.",

To Reproduce
1- follow the documentation to install serverless offline (https://github.com/bboure/serverless-appsync-simulator)
2- run serverless offline
3- call appsync API from the postman

Expected behavior
It must be able to query data using the integer variable without error

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
image

image

Cannot use the plugin with multiple AppSync APIs

Describe the bug
I have a serverless project with multiple AppSync APIs configured.

E.g.

custom:
  appSync:
    - name: api-one
       ...
    - name: api-two
       ...
    - name: api-three
       ...

When deploying the stack locally with sls offline start, I can only make requests against the first API defined in the list. Trying to make requests on other APIs returns an error stating that the operation doesn't exist.

Cannot query field "getField" on type "Query"."

To Reproduce

  1. Create a project with two or more AppSync APIs.
  2. Start it with sls offline start.
  3. Make a request against any API except the first one.

Expected behavior
An endpoint (or host on different ports) exist for each AppSync API

Unknown operation name: TransactWriteItems

I'm trying to make a TransactWriteItems request to DynamoDB Local and I'm getting the following error message:

"message": "Unknown operation name: TransactWriteItems",
"errorType": null,
"data": null,
"errorInfo": null,
"path": [
"createProduct"
],
"locations": [
{
"line": 2,
"column": 5,
"sourceName": "GraphQL request"
}
]

My package.json dependencies:

"serverless-appsync-plugin": "^1.3.1",
"serverless-appsync-simulator": "^0.6.0",
"serverless-dynamodb-local": "^0.2.39",
"serverless-offline": "^6.4.0",
"serverless-stack-output": "^0.2.3"

RelationalDataLoader: database connections aren't closed

Describe the bug
I keep having to restart sls offline because my database server is at it's maximum amount of connections.

To Reproduce
Run a couple of GQL queries, then run SHOW PROCESSLIST.
You will see numerous connections that are still left open, and won't get closed until forcefully restarting sls-offline.

Expected behavior
Connections get closed after a GQL query has been executed.

GetAttResolvers not found in params file

Thank you to all contributors for this library! I am having trouble getting my resolvers to run with the following setup in my serverless.yml file. I think I need to make a change to the getAttMap option in the custom section but I'm not sure how to resolve it. Any advice on how to resolve this?

My dataSources gets the IAMRole Arn like so:

dataSources:
  - type: AWS_LAMBDA
    name: getBorrower
    config:
      functionName: getBorrower
      serviceRoleArn: { Fn::GetAtt: [AWSAppSyncIAMRole, Arn] }

This gives the following error:

Fn::GetAttResolvers not found in params file: AWSAppSyncIAMRole

For reference, the resources part of my serverless.yml file.

resources:
  Resources:
    AWSAppSyncIAMRole:
      Type: AWS::IAM::Role

DynamoDB batch operations fail with error 'not implemented'

Describe the bug
When invoking a resolver that causes a DynamoDB batch operation on my local serverless API, I receive an error stating 'GraphQL error: Operation BatchPutItem not implemented'.

To Reproduce

  • Create a resolver and mapping template which runs a BatchPutItem request to DynamoDB
  • Run the mutation

Expected behavior
Inline with how AppSync itself behaves, I'd expect that the BatchPutItem performs as any other DynamoDB operation does, in this case by inserting all appropriate records into the DB

Screenshots
N/A

Additional context
N/A

Watchman prevents AppSync Simulator

Describe the bug
Trying to execute the AppSync Emulator briefly starts it, but crashes shortly after with a unhelpful error message. Searching it on Google doesn't seem to get anything else, really.

Serverless: Load command interactiveCli
[<omitted because there's a lot of commands>]
Serverless: Load command dev
Serverless: Invoke offline:start
AppSync Simulator: AppSync endpoint: http://192.168.15.107:20002/graphql
AppSync Simulator: GraphiQl: http://192.168.15.107:20002
Watchman:  spawn watchman ENOENT
 
  Error --------------------------------------------------
 
  Error: spawn watchman ENOENT
      at Process.ChildProcess._handle.onexit (internal/child_process.js:269:19)
      at onErrorNT (internal/child_process.js:465:16)
      at processTicksAndRejections (internal/process/task_queues.js:80:21)
 
  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com
 
  Your Environment Information ---------------------------
     Operating System:          linux
     Node Version:              14.15.4
     Framework Version:         1.75.1
     Plugin Version:            3.6.16
     SDK Version:               2.3.1
     Components Version:        2.32.0

To Reproduce
My current serverless.yml file uses the following plugins

plugins:
  - serverless-appsync-plugin
  - serverless-pseudo-parameters
  - serverless-plugin-warmup
  - serverless-appsync-simulator
  - serverless-offline

Expected behavior
I just expected at least a better error message, honestly. I'm just trying to configure it to replace @conduitvc/appsync-emulator-serverless.

Screenshots
N/A

Additional context
N/A

Feature Request: Aurora/Data API Simulation

Is your feature request related to a problem? Please describe.
I am looking to build out an application using App Sync and the Aurora Serverless.
From what I have read in the resolver tutorial the VTL for Aurora Serverless statements is really simple, but it's not clear how this could be run offline.
From what I can tell looking over this library it seems to focus around support for DynamoDB.

Describe the solution you'd like
I would like to be able to point at a local MySQL or Postgres database and have the appsync simulator run statements against that.

Describe alternatives you've considered
I am still in the initial investigation of AWS and AppSync in general so I don't personally have a lot of context into this as of yet.
I would love to hear feedback from others on possible solutions to this.

Can't start offline: not finding mappingTemplates?

Thanks for creating this plugin.
When I'm using serverless-appsync-simulator 0.3.4 I get an error when running offline:

AppSync Simulator: TypeError: (appSyncConfig.mappingTemplates || []).flat is not a function

I also tried making file references since I saw an issue where file mapping support was added.

Here is the relevant part of my serverless config:

plugins:
  - serverless-pseudo-parameters
  - serverless-appsync-simulator
  - serverless-appsync-plugin
  - serverless-offline
functions:
  auth:
    handler: functions/auth/handler.fetch
    cors: true
  getPost:
    handler: functions/getPost/handler.fetch
    cors: true
custom:
  serverless-offline:
    port: 3001
  region: ${opt:region, self:provider.region}
  appSync:
    mappingTemplates:
      - type: Query
        dataSource: LambdaSource
        field: getPost
        # request: "query-getpatients-request.vtl"
        # response: "common-response.vtl"
    dataSources:
      - type: AWS_LAMBDA
        name: LambdaSource
        description: "Lambda DataSource"
        config:
          functionName: graphql
          lambdaFunctionArn: ${self:provider.role}
          serviceRoleArn: ${self:provider.role}

Watchman: spawn watchman ENOENT -

I am getting the following error when starting on windows:

Watchman: spawn watchman ENOENT

Error ---------------------------------------------------

Error: spawn watchman ENOENT
at Process.ChildProcess._handle.onexit (internal/child_process.js:269:19)
at onErrorNT (internal/child_process.js:465:16)
at processTicksAndRejections (internal/process/task_queues.js:80:21)

Below is the full stack trace:

Serverless: Invoke offline:start
AppSync Simulator: backend-starter-vivekt AppSync endpoint: http://172.20.240.1:20002/graphql
AppSync Simulator: backend-starter-vivekt GraphiQl: http://172.20.240.1:20002
offline: Starting Offline: dev/us-east-1.
[offline] options: {
allowCache: false,
apiKey: 'd41d8cd98f00b204e9800998ecf8427e',
corsAllowCredentials: true,
corsAllowHeaders: [ 'accept', 'content-type', 'x-api-key', 'authorization' ],
corsAllowOrigin: [ '' ],
corsExposedHeaders: [ 'WWW-Authenticate', 'Server-Authorization' ],
disableCookieValidation: false,
dockerHost: 'localhost',
dockerHostServicePath: null,
dockerNetwork: null,
dockerReadOnly: true,
enforceSecureCookies: false,
functionCleanupIdleTimeSeconds: 60,
hideStackTraces: false,
host: 'localhost',
httpPort: 4040,
httpsProtocol: '',
lambdaPort: 3002,
layersDir: null,
noAuth: false,
noPrependStageInUrl: false,
noTimeout: false,
prefix: '',
printOutput: false,
resourceRoutes: false,
useChildProcesses: false,
useDocker: false,
useWorkerThreads: false,
webSocketHardTimeout: 7200,
webSocketIdleTimeout: 600,
websocketPort: 3001,
corsConfig: {
credentials: true,
exposedHeaders: [ 'WWW-Authenticate', 'Server-Authorization' ],
headers: [ 'accept', 'content-type', 'x-api-key', 'authorization' ],
origin: [ '
' ]
}
}
Watchman: spawn watchman ENOENT

Error ---------------------------------------------------

Error: spawn watchman ENOENT
at Process.ChildProcess._handle.onexit (internal/child_process.js:269:19)
at onErrorNT (internal/child_process.js:465:16)
at processTicksAndRejections (internal/process/task_queues.js:80:21)

Get Support --------------------------------------------
Docs: docs.serverless.com
Bugs: github.com/serverless/serverless/issues
Issues: forum.serverless.com

Your Environment Information ---------------------------
Operating System: win32
Node Version: 14.16.1
Framework Version: 2.40.0
Plugin Version: 4.5.3
SDK Version: 4.2.2
Components Version: 3.9.2

offline: Offline [http for lambda] listening on http://localhost:3002
offline: Function names exposed for local invocation by aws-sdk:

[offline] Lambda Invocation Routes (for AWS SDK or AWS CLI):

offline: [HTTP] server ready: http://localhost:4040 🚀
offline:
offline: Enter "rp" to replay the last request
error Command failed with exit code 1.

$util.map.copyAndRemoveAllKeys is not working

I'm developing appsync with serverless-framewrok.
I use dynamodb so I implemented vtl resolver files.
But copyAndRemoveAllKeys is not working.

See the following example code.
This is a respose.vtl code.

#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
#set($messages = $ctx.result.items)
#set($mergedMessages = [])
#set($users = $ctx.prev.result.items)
#foreach($m in $messages)
  #set($uid = $m.uid)
  #foreach($user in $users)
    #if($uid == $user.id)
      #set($m = $util.map.copyAndRemoveAllKeys($m, ["uid"])) ## This line.
      $util.qr($m.put("user", $user))
      $util.qr($mergedMessages.add($m))
      #break
    #end
  #end
#end
#set($result = { "items": $mergedMessages })
$util.toJson($result)

This always returns null and no error occurred.
I deployed this code and query it.
Unfortunately, I could retrieve expected response, not null.

query

query MyQuery {
  listChatMessages(groupId: "group-001") {
    items {
      id
      postDate
      user {
        color
        groupId
        id
      }
    }
  }
}

AppSync console result

{
  "data": {
    "listChatMessages": {
      "items": [
        {
          "id": "group-001",
          "postDate": "2021-06-23T01:00:01Z",
          "user": {
            "color": "blue",
            "groupId": "group-001",
            "id": "user-001"
          }
        },
        {
          "id": "group-001",
          "postDate": "2021-06-23T01:02:01Z",
          "user": {
            "color": "red",
            "groupId": "group-001",
            "id": "user-002"
          }
        }
      ]
    }
  }
}

Local AppSync Simulator

{
  "data": {
    "listChatMessages": null
  }
}

Is this bug?

Environment

"dependencies": {
    "serverless-appsync-plugin": "^1.11.3",
    "serverless-appsync-simulator": "^0.17.0",
    "serverless-dynamodb-local": "^0.2.39",
    "serverless-offline": "^7.0.0",
    "webpack": "^5.40.0",
    "webpack-cli": "^4.7.2",
    "webpack-node-externals": "^3.0.0"
  }

API server start fails using Fn::GetAtt with no Resources block

Describe the bug
I'm experiencing something similar to this issue, although my error instead is AppSync Simulator: TypeError: Cannot read property 'findWrappedResource' of undefined (same error as this issue) and thus the simulator fails to start.

In my case, I'm using serverless-appsync-plugin's default logConfig:

      logConfig:
        loggingRoleArn: { Fn::GetAtt: [AppSyncLoggingServiceRole, Arn] } # Where AppSyncLoggingServiceRole is a role with CloudWatch Logs write access
        level: ERROR
        excludeVerboseContent: false

Even though I've defined the following in custom.appsync-simulator in my serverless.yml:

    getAttMap:
      AppSyncLoggingServiceRole:
        Arn: "mockAppSyncLoggingServiceRoleArn"

To Reproduce
Add

      logConfig:
        loggingRoleArn: { Fn::GetAtt: [AppSyncLoggingServiceRole, Arn] }
        level: ERROR
        excludeVerboseContent: false

to custom.appSync and

    getAttMap:
      AppSyncLoggingServiceRole:
        Arn: "mockAppSyncLoggingServiceRoleArn"

in custom.appsync-simulator in serverless.yml

Expected behavior
There should be no error when starting the API server and the value should be taken from custom.appsync-simulator.getAttMap.

Screenshots

Additional context
Similar to this issue, I've been able to circumvent the error by defining an empty resources block like so:

resources:
  Resources: # nothing here
plugins:
  - serverless-appsync-simulator
  - serverless-offline
  - serverless-appsync-plugin

but with no resources defined, which, as far as I can tell, creates a ResourcesNode so the findWrappedResource property is at least defined and the simulator starts.

This is a decent workaround at the moment, since I don't actually require the loggingRoleArn locally so this isn't high priority by any means. But the requirement to have resources defined even if it's empty creates a bit of cognitive dissonance and should not be necessary.

As always, thanks for your work on this plugin, it has made debugging and working with AppSync APIs locally actually possible for me 👍

RelationalDataLoader support for Variable Map

Is your feature request related to a problem? Please describe.
We use a lot of variable maps in our VTLs, and using the recently released [RelationalDataLoader](https://github.com/bboure/serverless-appsync-simulator/pull/110) implementation, we've noticed that some of our templates were failing. Here's an example:

Here's an example:

{
  "version": "2018-05-29",
  "statements": [
    "INSERT INTO address (id, user_id, name, phone, street, unit, city, state, zip_code) VALUES (:ID, :USER_ID, INITCAP(:NAME), :PHONE, :STREET, :UNIT, :CITY, :STATE, :ZIP_CODE)"
  ],
  "variableMap": {
    ":ID": "$util.autoId()",
    ":USER_ID": "$ctx.identity.sub",
    ":NAME": "$ctx.args.input.name.replace("'","''")",
    ":PHONE": "$ctx.args.input.phone.replaceAll("\D","")",
    ":STREET": "$ctx.args.input.street.replace("'","''")",
    ":UNIT": $util.toJson($util.defaultIfNullOrEmpty($ctx.args.input.unit.replace("'","''"), null)),
    ":CITY": "$ctx.args.input.city.replace("'","''")",
    ":STATE": "$ctx.args.input.state",
    ":ZIP_CODE": "$ctx.args.input.zipCode"
  }
}

This insert fails today 😢 because the DB client sees :ID instead of proper values...

Describe the solution you'd like
Ideally, we should handle gracefully all variableMap inputs, adding them to the SQL Query accordingly to the DB Schema demands... but sometimes we do not have the information on the input type required.

The proposed solution is to add an injectVariables function that includes the variables in the statement according to their expected types.

Describe alternatives you've considered
Another alternative would be to migrate all our VTLs to direct inputs... but that is to offer less parity to the actual AppSync Cloud behavior.

Usage with Typescript

Hello. When using this plugin together with the serverless-plugin-typescript plugin, the simulator automatically looks in our .build directory to find the compiled Lambda functions.

However, it also attempts to find the schema.graphql in this same directory which fails as this file only exists in the root. I don't see an option to tell it to find the schema in a different location from the Lambda functions.

Running cp schema.graphql .build/ before starting this plugin works, but that breaks hot reloading.

What's the proper way to use this plugin together with the Typescript plugin?

Supporting Multiple Lambda Runtimes

Is your feature request related to a problem? Please describe.
It currently seems that this package supports only javascript lambda resolvers. Am I missing something? Many other languages could be used with serverless. Additionally, this tool is then coupled with an opinion that the lambda resolvers cannot be written in languages outside of javascript.

Describe the solution you'd like
I don't know the first thing about Javascript ( I am a python and rust dev mostly), so bear with me.

With the dependency on the serverless offline plugin, it seems instead we could invoke the lambda with the aws sdk as the method described here in the serverless offline docs. Since this plugin is already required, there is no net gain in dependencies. The amplify-nodejs-function-runtime-provider could be removed in favor of adding the aws-sdk and using the already required serverless-offline

Describe alternatives you've considered
For a lot of languages (outside of what amplify supports) there are no alternatives for local development. Even inside of the amplify ecosystem, if some of its opinionated defaults works for you, you are kicked to doing everything by hand or using serverless. To that end, I think there should be some demand for this.

Additional context
I am willing to contribute this back if the maintainers are willing to have the feature and willing to bear with some terrible javascript code as a I learn. If its not inline with the direction, I can always work on a custom solution.

API server start fails when using Fn::GetAtt when Resources are empty

Describe the bug
I'm passing the AppSync GraphQL API endpoint to functions via intrinsic function in environment variables. It works with no problem when deployed. But when I try running it locally, I get error:

AppSync Simulator: TypeError: Cannot read property 'GraphQlApi' of undefined

To Reproduce
Put into provider.environment for examlpe:

API_URL: { 'Fn::GetAtt': ['GraphQlApi', 'GraphQLUrl'] }

and run $ serverless offline start

Expected behavior
There should be no error when starting the API server and the value should be taken from custom.appsync-simulator.getAttMap.

Screenshots
image

Additional context
I figured out that this issue comes from the cfn-resolver-lib.
To be exact - from ResourcesNode.findWrappedResource

The error disappears when I put some contents into the Resources for example like this:

resources:
  Resources:
    abc: def

it causes, that this.wrappedObject is not undefined anymore because addChild method was called on ResourcesNode and thus this.wrappedObj = {} was performed.

Possible quick solution that comes to my mind is doing something like this in index.js:

- Resources: this.serverless.service.resources?.Resources || {},
+ Resources: this.serverless.service.resources?.Resources || { a: 'b' }, 

But that's quite ugly solution and I don't really like it.

Any ideas how to properly fix it as easily as possible?

Big responses seem to "get lost" - they time out

Describe the bug
When I return a big long array, the response seems to be loading indefinitely and then it times-out.

I did some digging and I discovered that the issue comes from here:
https://github.com/aws-amplify/amplify-cli/blob/master/packages/amplify-nodejs-function-runtime-provider/src/utils/execute.ts#L94

According to this discussion the limit for process.send payload seems to be 65536. And when I tested it, it really stopped working after crossing this boundary. Unfortunately it doesn't throw any error.

To Reproduce
Return some big long array as response.

Expected behavior
Whole array should be returned in the response. There should be no timeouts.

AppSync Simulator: TypeError: FnSplit is not a constructor

Describe the bug
Unable to start appsync in local using this plugin.

getting error like this

AppSync Simulator: TypeError: FnSplit is not a constructor

using these packages

"serverless-appsync-simulator": "^0.3.4",
"serverless-offline": "^5.12.1",
"serverless-appsync-plugin": "1.1.2",
"serverless": "^1.61.2",

added in plugin sections like this

plugins:
  - serverless-webpack
  - serverless-appsync-simulator
  - serverless-offline

Screenshot 2020-01-17 at 12 17 15 PM

'selectionSetGraphQL' parameter from context incorrectly contains the 'arguments'

Describe the bug
I have a Lambda Data Source for a query type in the form (from schema file) -

type Query {
    modelQuery(filters: [Filters!], groupingCriteria: [Criteria!]!): [ModelType!]!
}

When I start the appsync simulator, I am able to connect to the local AppSync instance and query it using the 'aws-amplify' library where I send in a request of the form -

query{ 
  modelQuery(groupingCriteria: { keyId: "sector" })
  {
    variableA
    variableB  
  }

The above query hits the Local Lambda Data Source correctly, but incorrectly passes in the 'arguments' into the 'selectionSetGraphQL' field (from the Invocation payload of the request) (check: https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html) -
"selectionSetGraphQL": "{keyId: \"sector\"}) {\n variableA\n variableB\n}"

For comparison, the above works correctly in AppSync proper -
"selectionSetGraphQL": "{\n variableA\n variableB\n}"

To Reproduce

The relevant serverless mapping template config is:

      - dataSource: ModelQuery
        type: Query
        field: modelQuery
        request: "modelQuery-request-mapping-template.vtl"
        response: "modelQuery-response-mapping-template.vtl"

'modelQuery-request-mapping-template.vtl' VTL file:

{
"version": "2017-02-28",
"operation": "Invoke",
"payload": {
"field": "modelQuery",
"arguments":  $utils.toJson($context.arguments),
"selectionSetGraphQL": $utils.toJson($context.info.selectionSetGraphQL)
}
}

Expected behavior

The selectionSetGraphQL parameter should pass in the value as it is in AWS AppSync with no arguments being included into the selectionSetGraphQL string -

"selectionSetGraphQL": "{\n variableA\n variableB\n}"

rather than
"selectionSetGraphQL": "{keyId: \"sector\"}) {\n variableA\n variableB\n}"

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
Add any other context about the problem here.

v0.17 breaks the hotreload (lambdas changes are ignored)

Describe the bug
Starting at v0.17.0 the hot-reload feature gets broken, changes are ignored.

To Reproduce
Setup a template with webpack build to a custom folder, and set this custom folder as an appsync-simulator location.

Expected behavior
Hotreload should take lambda changes into account, even with a custom location path.

Additional context
The lambda execution context does not seem to be passed anymore (location & loadLocalEnv) when executing a direct Axios request against the offline endpoint instead of using the amplify invoke util.

AppSync CloudFormation resources not generated when running the simulator

I was investigating an existing issue #108 but I think the issue is different from what is discussed in that ticket.

In addition to the error I also see warnings like Fn::GetAttResolvers not found in params file: GraphQlApi. This is because the CFN resolver can not find my GraphQlApi CloudFormation resource. This causes the !GetAtt function to return a value that the !Split function can not handle.

When I log this.serverless.service.resources right before this line (https://github.com/bboure/serverless-appsync-simulator/blob/master/src/index.js#L70) I indeed don't see any GraphQL resources. So any !GetAtt functions that reference AppSync resources will fail, which causes the appsync simulator to not start up.

Is there any way to have the AppSync resources already generated when starting the simulator? The serverless-appsync-plugin is already listed higher than the simulator in my plugin configuration.

AppSync Simulator: TypeError: Cannot read property 'path' of undefined

Describe the bug
Getting error while setting up serverless-appysnc-emulator on windows
AppSync Simulator: TypeError: Cannot read property 'path' of undefined
To Reproduce
Steps to reproduce the behavior

Expected behavior
A clear and concise description of what you expected to happen.

TypeError: Cannot read property 'path' of undefined
at getAppSyncConfig (C:\Users\Administrator\Documents\appdatasoft\sumiventures\codemarket\parkyourselfbackend\node_modules\serverless-appsync-simulator\lib\getAppSyncConfig.js:247:38)
at ServerlessAppSyncSimulator.initServer (C:\Users\Administrator\Documents\appdatasoft\sumiventures\codemarket\parkyourselfbackend\node_modules\serverless-appsync-simulator\lib\index.js:85:50)
at Client. (C:\Users\Administrator\Documents\appdatasoft\sumiventures\codemarket\parkyourselfbackend\node_modules\serverless-appsync-simulator\lib\index.js:147:14)
at Client.emit (events.js:315:20)
at Client.EventEmitter.emit (domain.js:482:12)
at BunserBuf. (C:\Users\Administrator\Documents\appdatasoft\sumiventures\codemarket\parkyourselfbackend\node_modules\fb-watchman\index.js:90:14)
at BunserBuf.emit (events.js:315:20)
at BunserBuf.EventEmitter.emit (domain.js:482:12)
at BunserBuf.process (C:\Users\Administrator\Documents\appdatasoft\sumiventures\codemarket\parkyourselfbackend\node_modules\bser\index.js:292:10)
at C:\Users\Administrator\Documents\appdatasoft\sumiventures\codemarket\parkyourselfbackend\node_modules\bser\index.js:247:12
at processTicksAndRejections (internal/process/task_queues.js:79:11)

 For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.

Get Support --------------------------------------------
Docs: docs.serverless.com
Bugs: github.com/serverless/serverless/issues
Issues: forum.serverless.com

Your Environment Information ---------------------------
Operating System: win32
Node Version: 12.18.2
Framework Version: 2.12.0
Plugin Version: 4.1.2
SDK Version: 2.3.2
Components Version: 3.4.1

Screenshots
If applicable, add screenshots to help explain your problem.
image

Additional context
Add any other context about the problem here.

Connection to external DynamoDB does not work if you have protected Dynamo with Session Token

The security token included in the request is invalid
I Have included appsync-simulator inside my serverless project, I'm trying to connect it with my remote DynamoDB resource on AWS that is protected through a session token.

"serverless-appsync-simulator" give me the ability to configure 4 parameter to connect itself with external DynamoDB:

custom:
  appsync-simulator:
    apiKey: 0123456789
    port: 20002
    dynamoDb:
      endpoint: https://dynamodb.eu-central-1.amazonaws.com
      region: eu-central-1
      accessKeyId: DEFAULT_ACCESS_KEY
      secretAccessKey: DEFAULT_SECRET

(Default values of accessKeyId and secretAccessKey are written on my .aws/credential file!)
I have also tried to write accessKeyId and secretAccessKey inside my "serverless.yml" file.

If I run "sls offline start" and try to make a query, AppSync Simulator give me back an error message:

message "The security token included in the request is invalid."
code: "UnrecognizedClientException"

I have an updated token in my .aws/credential file, so I think that the problem could be that AppSync Simulator does not support authentication with the session token.

My expectation is to find another configuration parameter under dynamoDb:

custom:
  appsync-simulator:
    apiKey: 0123456789
    port: 20002
    dynamoDb:
      endpoint: https://dynamodb.eu-central-1.amazonaws.com
      region: eu-central-1
      accessKeyId: DEFAULT_ACCESS_KEY
      secretAccessKey: DEFAULT_SECRET
      sessionToken: DEFAULT_SESSION_TOKEN ???

Is there a workaround to solve this issue?

Index n is out of bound when trying to manipulate AWS::StackId Ref

Trying to split the StackId by using a Fn::Split inside a Fn::Select would crash the resolver.
I'm not sure if the issue is related to AppSync simulator or the offline plugin which would not resolve the StackId Ref because hardcoding it seems to fix the issue.

Error

AppSync Simulator: Index 2 is out of bound.

Relevant crashing resource example

  CognitoUserPoolDomain:
    Type: AWS::Cognito::UserPoolDomain
    Properties:
      # What is before .auth.REGION.amazoncognito.com
      # @note get random UUID from the stack Id
      # @see https://stackoverflow.com/a/67162053/13169049
      Domain:
        Fn::Join:
          - '-'
          - - "myservicename"
            - Fn::Select:
                - 4
                - Fn::Split:
                    - '-'
                    - Fn::Select:
                        - 2
                        - Fn::Split:
                            - /
                            - Ref: AWS::StackId

It looks like the AWS::StackId does not get resolved by the offline plugin, hardcoding the StackId fixes the issue

  CognitoUserPoolDomain:
    Type: AWS::Cognito::UserPoolDomain
    Properties:
      # What is before .auth.REGION.amazoncognito.com
      # @note get random UUID from the stack Id
      # @see https://stackoverflow.com/a/67162053/13169049
      Domain:
        Fn::Join:
          - '-'
          - - "myservicename"
            - Fn::Select:
                - 4
                - Fn::Split:
                    - '-'
                    - Fn::Select:
                        - 2
                        - Fn::Split:
                            - /
                            - arn:aws:cloudformation:us-west-2:123456789012:stack/teststack/51af3dc0-da77-11e4-872e-1234567db123

Any help would be greatly appreciated!

Config variables are unresolved from Serverless config

Describe the bug
While attempting to use an environment variable as my apiKey option, I realized that the variables weren't being resolved before reaching the plugin and were evaluating as-is (i.e, apiKey would evaluate to ${env:API_KEY}

To Reproduce
Attempt to use any variable in the options for appsync-simulator inside your Serverless configuration.

Expected behavior
Variables should be resolved!

Updating GraphQL to major version 16 breaks simulator

Describe the bug

Our project uses multiple schema files (to make editing the whole schema easier), and trying to update GraphQL from ^15.5.3 to ^16.2.0 makes serverless-appsync-simulator stop working, with the following error:

AppSync Simulator: TypeError: graphql.getDescription is not a function

A bit investigation found that serverless-appsync-simulator is using merge-graphql-schemas which is deprecated and should be replaced according to a guide: https://www.graphql-tools.com/docs/migration/migration-from-toolkit

I also tinkered a bit and generated an stacktrace pointing to the TypeError in question, if that's useful:

at pushComment (project_root/node_modules/@graphql-toolkit/schema-merging/index.cjs.js:117:15)
at collectComment (project_root/node_modules/@graphql-toolkit/schema-merging/index.cjs.js:93:5)
at project_root/node_modules/@graphql-toolkit/schema-merging/index.cjs.js:663:17
at Array.reduce (<anonymous>)
at mergeGraphQLNodes (project_root/node_modules/@graphql-toolkit/schema-merging/index.cjs.js:658:18)
at mergeGraphQLTypes (project_root/node_modules/@graphql-toolkit/schema-merging/index.cjs.js:755:25)
at Object.mergeTypeDefs (project_root/node_modules/@graphql-toolkit/schema-merging/index.cjs.js:710:22)
at mergeTypes (project_root/node_modules/merge-graphql-schemas/index.cjs.js:24:26)
at getAppSyncConfig (project_root/node_modules/serverless-appsync-simulator/lib/getAppSyncConfig.js:251:50)
at ServerlessAppSyncSimulator.initIndividualServer (project_root/node_modules/serverless-appsync-simulator/lib/index.js:140:50)
at ServerlessAppSyncSimulator.initServers (project_root/node_modules/serverless-appsync-simulator/lib/index.js:135:12)
at ServerlessAppSyncSimulator.startServers (project_root/node_modules/serverless-appsync-simulator/lib/index.js:108:14)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async PluginManager.runHooks (project_root/node_modules/serverless/lib/classes/PluginManager.js:573:35)
at async PluginManager.invoke (project_root/node_modules/serverless/lib/classes/PluginManager.js:610:9)
at async PluginManager.run (project_root/node_modules/serverless/lib/classes/PluginManager.js:672:7)
at async Serverless.run (project_root/node_modules/serverless/lib/Serverless.js:468:5)
at async project_root/node_modules/serverless/scripts/serverless.js:836:9

To Reproduce
Create a Serverless AppSync project (all dependencies updated) which uses multiple .graphql files and a glob pattern so schema merging is required.

Expected behavior
I expected the simulator to work, because it works with multiple schemas w/ GraphQL ^15.5.3.

Screenshots
image

Additional context
package.json versions of all relevant dependencies:

{
    "graphql": "^16.2.0",
    "serverless": "^2.66.2",
    "serverless-appsync-plugin": "^1.12.1",
    "serverless-appsync-simulator": "^0.19.2",
    "serverless-offline": "^8.2.0",
}

serverless.yml appsync schema:

  appSync:
    name: ${self:custom.stack-prefix}-appsync
    schema: "serverless/graphql/**/*.graphql"

Error: UnauthorizedException: Missing authorization

A few seconds after running sls offline start (no additional action required) the following error occurs:

Error: UnauthorizedException: Missing authorization

This error keeps occurring every few seconds.

Note that the API works correctly and I'm able to make graphql requests and receive results.

Amplify crashes while calling DynamoDB if AWS Credentials are not set

Hi @bboure !

First of all, thanks for this plugin.

I've tested it and adjusted a few things (PR right up), but I've encountered an issue where I wasn't sure about the solution.

In my local environment I do not have a "default" profile inside AWS configuration. While testing the plugin I got this error:

Error while executing Local DynamoDB
{
    "operation": "Scan",
    "limit": 20,
    "nextToken": null
}
Error: connect EHOSTUNREACH 169.254.169.254:80
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1129:14) {
  message: 'Missing credentials in config',
  errno: 'EHOSTUNREACH',
  code: 'CredentialsError',
  syscall: 'connect',
  address: '169.254.169.254',
  port: 80,
  time: 2019-12-09T11:01:12.008Z,
  originalError: {
    message: 'Could not load credentials from any providers',
    errno: 'EHOSTUNREACH',
    code: 'CredentialsError',
    syscall: 'connect',
    address: '169.254.169.254',
    port: 80,
    time: 2019-12-09T11:01:12.008Z,
    originalError: {
      message: 'EC2 Metadata roleName request returned error',
      errno: 'EHOSTUNREACH',
      code: 'EHOSTUNREACH',
      syscall: 'connect',
      address: '169.254.169.254',
      port: 80,
      time: 2019-12-09T11:01:12.007Z,
      originalError: [Object]
    }
  }
}

I tried setting some invalid credentials:

[default]
aws_access_key_id=AKIAFAIL
aws_secret_access_key=AKIAFAIL

And the DynamoDB call went on without further issues.

Since amplify requires the amplify init / amplify configure commands before running, this error would not show on the original library.

I'm not sure what the correct solution would be in this case, though.
I would not want an user to have a set of AWS credentials to work offline with this plugin.

Here are a couple of possible solutions:

  • Setting a fake set of credentials inside the init scripts
  • Using serverless provider configuration with the fake credentials as a default

WDYT?

Upgrading to 0.7.1 throws Error: GUID must provide "serialize" function

Describe the bug
Upgrading to serverless-appsync-simulator version 0.7.1 has caused the following error to be thrown when running the local server:

Error: GUID must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.

To Reproduce
Upgrade to 0.7.1. Use these dependencies as well

"serverless": "^1.60.0",
"serverless-appsync-plugin": "^1.1.2",
"serverless-appsync-simulator": "^0.7.1",
"serverless-offline": "^5.12.1",

And create a graphql schema making use of only ID, String, Int, Float types and types based off of enums.
We're also using various aws decorators like @aws_subscribe

Expected behavior
The api should start successfully and not die on the error listed above

Screenshots
Screenshot 2020-10-29 at 09 46 55

Additional context
I apologize for not providing more info, but I'm not sure where exactly this error is coming from. I'm moreso sharing because I cannot find any information elsewhere, and am wondering if anyone else has the same issue

Lambda Data source failed with the following error {}

Describe the bug
Unable to get error message from resolvers in pipeline
Lambda Data source failed with the following error {}

To Reproduce
create a pipeline functions, throw exception in first function of the pipeline, try to catch error message in VTL template or the response from appsync

Expected behavior
Should be able to capture error message in VTL

Screenshots
Screenshot 2020-05-18 at 8 10 31 PM

Additional context
Getting empty error object in Lambda dataloader exception block

Bug when starting AppSync Simulator: TypeError: strToSplit.split is not a function

Bug Intro

To reproduce this a error you should have serverless-appsync-simulator and serverless-offline plugins and cloudfront resource configuration for appsync.

When starting offline mode with serveress offline start I got this error:

AppSync Simulator: TypeError: strToSplit.split is not a function

Bug description

The bug is caused by appsync-simulator if you have Fn::Split CF function in DomainName of Origin section. See example below.

Resources:
  PublicApiDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Enabled: true
        PriceClass: PriceClass_100
        HttpVersion: http2
        Comment: ${self:custom.PublicApiDomain}
        Aliases:
          - ${self:custom.PublicApiDomain}
        CustomErrorResponses: []
        ViewerCertificate:
          AcmCertificateArn: ${ssm:/${sls:stage}/global/acm_certificate_arn}
          SslSupportMethod: sni-only
        Origins:
          - Id: PublicApiOrigin
            DomainName:
              Fn::Select:
                - '2'
                - Fn::Split:
                    - /
                    - Fn::GetAtt:
                        - "Eventapipub${sls:stage}GraphQlApi"
                        - GraphQLUrl

Temporary workaround

Currently the only solution do disable this error in offline mode is to comment cf code for distribution.

Pass all the environment variables to the functions

Is your feature request related to a problem? Please describe.
When Lambda function is deployed, the environment variables like AWS_REGION are implicitly set by AWS itself. So for example in NodeJS the aws-sdk can extract the region value from the environment variable. But when locally using serverless-appsync-simulator, only environment variables defined in serverless.yml file are passed to the function and thus the SDK throws an error, because it can't find the region in the environment variable.

Code example:

How I would like the code to look like 🙂 :

import AWS from 'aws-sdk'

const dynamodb = new AWS.DynamoDB()
const client = await dynamodb.getItem({
  TableName: process.env.DYNAMODB_TABLE_NAME,
  Key: {
    id: {
      S: `${client.id}`
    }
  }
}).promise()

How it has to be done now 😢 :

import AWS from 'aws-sdk'

const dynamodb = new AWS.DynamoDB({ region: 'ap-southeast-1' }) // region has to explicitly defined here
const client = await dynamodb.getItem({
  TableName: process.env.DYNAMODB_TABLE_NAME,
  Key: {
    id: {
      S: `${client.id}`
    }
  }
}).promise()

Describe the solution you'd like
Pass all the environment variables to the function.

During local development we are using env-cmd file through which we mock all the environment variables. So for example we define there AWS_REGION value.

Describe alternatives you've considered
I tried to set AWS_REGION environment variable in provider.environment, but later during deployment AWS CloudFormation throws and error, because it's a reserved environment variable name.

Error AppSync Simulator: TypeError: Cannot read property 'findWrappedResource' of undefined

Describe the bug
on serverless start i get a error
AppSync Simulator: TypeError: Cannot read property 'findWrappedResource' of undefined

To Reproduce
Got the current serverless.yml setup custom like this:
custom: name: ${self:service}-${self:provider.stage} dynamodb: start: port: 8039 appsync-simulator: port: 6239 dynamoDb: endpoint: "http://localhost:8039" serverless-offline: port: 4039 appSync: authenticationType: API_KEY name: ${self:custom.name} ......
resulting in this:
Schermafbeelding 2019-12-23 om 13 14 13

any advise on how to solve this error?

Unable to connect to websocket server for subscriptions

Describe the bug
The server appears to run fine, but when trying to connect from my frontend application I'm getting

Unhandled Runtime Error
Error: Connection handshake error

In my browser console I can see it trying to connect to the wrong websocket port

wss://localhost:62222/graphql?header=***

To Reproduce
Set up the plugin in the serverless file

// serverless.yml

appsync-simulator:
  port: 62222
  wsPort: 62223

package.json with these deps

"serverless": "^1.60.0",
"serverless-appsync-plugin": "^1.1.2",
"serverless-appsync-simulator": "0.5.0",
"serverless-offline": "^5.12.1",

Connect via the amplify library (we're using a React app)

import { Amplify } from 'aws-amplify'

export const awsConfig = {
  Auth: {
    // ...
  },
  aws_appsync_graphqlEndpoint: process.env.API_URL,
  // ...
  API: {
    graphql_endpoint: process.env.API_URL,
    // ...
  }
}

Amplify.configure(awsConfig)

And simply try and use a subscription somewhere in your frontend

Expected behavior
Websockets should connect and not throw errors when trying to use subscriptions

Screenshots
Screenshot 2020-10-29 at 12 26 48

Additional context
Possibly related issue? aws-amplify/amplify-cli#4264

I've also tried

  • Using the default ports
  • Setting the websocket server to use the same port

It looks to me like amplify simply does not connect to the right port. However I changed the source code to explicitly connect to the ws port and no luck; it throws the same error

AppSync Simulator: TypeError: (appSyncConfig.mappingTemplates || []).flat is not a function

plugins:
  - serverless-appsync-plugin
  - serverless-dynamodb-local # only if you need dynamodb resolvers and you don't have an external dynamodb
  - serverless-appsync-simulator
  - serverless-offline
custom:
  appSync:
    name: stores-api
    schema: schema.graphql
    authenticationType: API_KEY
    mappingTemplatesLocation: mapping-templates
    mappingTemplates:
      - dataSource: hello
        type: Query
        field: hello
        request: Query.hello.request.vtl
        response: Query.hello.response.vtl
    dataSources:
      - type: AWS_LAMBDA
        name: hello
        description: 'Lambda DataSource'
        config:
          functionName: hello
  appsync-offline:
    port: 62222
    dynamodb:
      server:
        port: 8000

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.