1
votes

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 !!

1
my lambdas using POST are also buggy. Amazon forces me to add a random query param to the request: /myPOSTendpoint?blah=123 does it work for you to add a query param? - gyc
I changed back my apollo server to version 2, end I finally got a request POST to work on the API Gateway test function on my aws account. I don't know what I change from before... If I understand the why and how, I'll post here my solutions! - rdhox

1 Answers

2
votes

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