简体   繁体   中英

Serverless framework + AWS + Lambda + DynamoDB + GraphQL + Apollo Server = Can't make POST Request Work

Ok, I'm on this problem since a few days.

I try to take this tutorial : https://serverless.com/blog/make-serverless-graphql-api-using-lambda-dynamodb/

And make it work with apollo-server-lambda. This tutorial help:

https://medium.com/vessels/apollo-server-serverless-graphql-bliss-68e8e15195ac

The problem is that nothing is working (for me) when you tried to use apollo server lambda with a real connection with DynamoDB. I got a list of errors that i can't remember anymore, it's just discouraging.

Here my code :

# serverless.yml
service: graphql-api

provider:
  name: aws
  runtime: nodejs6.10
  region: eu-west-3
  stage: dev
  environment:
    DYNAMODB_TABLE: ${self:service}-${self:provider.stage}
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:GetItem
        - dynamodb:UpdateItem
      Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"

resources:
  Resources:
    NicknamesTable:
      Type: 'AWS::DynamoDB::Table'
      Properties:
        AttributeDefinitions:
          - AttributeName: firstName
            AttributeType: S
        KeySchema:
          - AttributeName: firstName
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: ${self:provider.environment.DYNAMODB_TABLE}

functions:
  graphql:
    handler: handler.graphql
    events:
      - http:
          path: graphql
          method: post
          cors: true
      - http:
          path: graphql
          method: get
          cors: true

And my handler:

# handler.js
const AWS = require('aws-sdk');
const server = require("apollo-server-lambda");
const makeExecutableSchema = require('graphql-tools').makeExecutableSchema;
const dynamoDb = new AWS.DynamoDB.DocumentClient();

const promisify = foo => new Promise((resolve, reject) => {
    foo((error, result) => {
        if (error) {
            reject(error)
        } else {
            resolve(result)
        }
    })
})

const getGreeting = firstName => promisify(callback =>
    dynamoDb.get({
        TableName: process.env.DYNAMODB_TABLE,
        Key: { firstName },
    }, callback))
    .then(result => {
        if (!result.Item) {
            return firstName
        }
        return result.Item.nickname
    })
    .then(name => `Hello, ${name}.`)

// add method for updates
const changeNickname = (firstName, nickname) => promisify(callback =>
    dynamoDb.update({
        TableName: process.env.DYNAMODB_TABLE,
        Key: { firstName },
        UpdateExpression: 'SET nickname = :nickname',
        ExpressionAttributeValues: {
            ':nickname': nickname
        }
    }, callback))
    .then(() => nickname)

const typeDefs = `
    type Query {
        greeting(firstName: String!): String
    }
    type Mutation {
        changeNickname(
            firstName: String!
            nickname: String!
        ): String
    }
`;

const resolvers = {
    Query: {
        greeting: (_, { firstName }) => getGreeting(firstName),
    },
    Mutation: {
        changeNickname: (_, { firstName, nickname }) => changeNickname(firstName, nickname),
    }
};

exports.graphql = function (event, context, callback) {
    const callbackFilter = function (error, output) {
        output.headers = output.header || {};
        output.headers['Access-Control-Allow-Origin'] = '*';
        callback(error, output);
    };
    const handler = server.graphqlLambda({ schema: makeExecutableSchema({ typeDefs, resolvers }) });

    return handler(event, context, callbackFilter);
};

I tried to used Apollo 1 and 2, nothing work. I'm back to the version 1 since there is more forum posts about it. Mostly I have "internal server error". I tried differents versions of server that i found on apollo docs but all my request failed, with curl on a terminal or directly on the API Gateway on AWS to test the function. I write the request body following this doc: https://www.apollographql.com/docs/apollo-server/requests.html

Here my cloudwatch log:

(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): SyntaxError: Unexpected token = in JSON at position 8

Any help would be greatly appreciate !!

Ok I figured out the problem. When you use the put function, you can't get the new item that you just insert in dynamoDB. You have to put "ReturnValues: 'ALL_OLD'" in your params object (first argument of the put function), like that no error is thrown, and you supposed to return the values you want since you just entered them in the db.

More details here:

https://github.com/aws/aws-sdk-js/issues/803

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM