serverless-appsync-simulator: 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":"tes@test.com","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. 📝 🙇

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 16 (4 by maintainers)

Most upvoted comments

The following PRs have been successfully merged and this issue is now closed! 🎉 https://github.com/aws-amplify/amplify-cli/pull/5608/files

It was very emotional to be able to commit to OSS for the first time in my life. I would like to thank everyone involved in this issue. Thank you so much guys! 🙌

@bboure Thank you for the suggestion. I have created a PR. 🛠️ https://github.com/aws-amplify/amplify-cli/pull/5608/files

@somq Thank you for your comment. 🙏 I fixed amplify-nodejs-function-runtime provider instead of amplify-util-mock, so I’ve created a new PR. 🙋

We’re also facing this issue when chaining lambda functions as query results. If we chain two functions f1 and f2 for a Query, we only get a valid return iff f1 and f2 return in time. Else the exit code 1 of either function stops GQL from resolving correctly.

Very much looking forward to the fix provided in https://github.com/aws-amplify/amplify-cli/pull/5608!

great, If this fixes your issue, a PR should be open on aws-amplify

I confirm your fix @nikaera, There is already a merged PR, prolly released in amplify-appsync-simulator@1.23..2 (didnt verify tho)

An amplify-appsync-simulator upgrade should not hurt anyway

great, If this fixes your issue, a PR should be open on aws-amplify

@bboure Oh, I just thought I’d verify, based on your opinion, by changing exit(1) to exit(0) and it always succeeds in running Lambda!! 👀 https://github.com/aws-amplify/amplify-cli/blob/master/packages/amplify-nodejs-function-runtime-provider/src/utils/execute.ts#L108

// node_modules/amplify-nodejs-function-runtime-provider/lib/utils/execute.js
// ...
process.on('message', async (options) => {
    try {
        const result = await invokeFunction(JSON.parse(options));
        process.stdout.write('\n');
        process.stdout.write(JSON.stringify({ result, error: null }));
    }
    catch (error) {
        process.send(JSON.stringify({
            result: null,
            error: {
                type: 'Lambda:Unhandled',
                message: error.message,
            },
        }));
    }
    // exit_1.default(1);
    exit_1.default(0);
});
//# sourceMappingURL=execute.js.map