Amplify-cli: User @model and Cognito

Created on 18 Oct 2019  路  8Comments  路  Source: aws-amplify/amplify-cli

* Which Category is your question related to? *
GraphQL

* What AWS Services are you utilizing? *
AppSync, Cognito

* Provide additional details e.g. code snippets *
I'm using the GraphQL API + Cognito and I'm trying to describe a model where I have something like this:

type List @model {
  id: ID!
  name: String!
  author: User @connection
}

type User @model {
  id: ID!
  name: String!
  picture: String
  email: String!
  phone_number: String!
  org: Org @connection(name: "OrgUsers")
}

type Org @model {
  id: ID!
  name: String!
  users: [User] @connection(name: "OrgUsers")
}

I want to be able to list all the users from an Organisation, get a User by Id, etc, using the GraphQL API. The thing is that I don't understand how can I associate the Cognito users with the ones in the model. My try was to create a new User in a Lambda with postConfirmation trigger, but I'm getting a cyclic dependency error (cognito -> postConfirmation -> graphqlapi -> cognito)... Also, it seems just wrong to have duplicated data between cognito and dynamodb. This seems a quite common use case but I can't find any information on the docs and in this repo. What am I missing?

graphql-transformer pending-response question

Most helpful comment

I create a function via amplify:

var AWS = require('aws-sdk');
var dynamodb = new AWS.DynamoDB();

exports.handler = (event, context, callback) => {
  console.log('add to database');
  var tableName = 'User dynamodb TABLE' // or set dynamic via process.env
  var userID = event.request.userAttributes.sub;

  dynamodb.putItem(   {
      TableName: tableName,
      Item: {
        id: {S: userID},
      },
    },
    function(err, data) {
      if (err) {
        console.log(err, err.stack); // an error occurred
        callback(err, null);
      } else {
        callback(null, data);
      }
    },
  );
};

In the cloudformation-template.json of your function (in amplify > backend > function) add this statement to lambdaexecutionpolicy area:

{
                            "Effect": "Allow",
                            "Action": [
                                "dynamodb:PutItem"
                            ],
                            "Resource": {
                                "Fn::Sub": [
                                    "arn:aws:dynamodb:${region}:${account}:table/*",
                                    {
                                        "region": {
                                            "Ref": "AWS::Region"
                                        },
                                        "account": {
                                            "Ref": "AWS::AccountId"
                                        }
                                    }
                                ]
                            }
                        }

All 8 comments

I created indeed a lambda function as a post confirmation trigger. What it does it sends the user ID to a dynamodb table. I also have been looking for other options, but if you want user data listed in your app this is your way.

@rpostulart Could you publish a gist explaining how did you insert it in a DynamoDB table? I added the Users table via amplify add api and it seems that I can't insert an item from Lambda if it was created that way

I create a function via amplify:

var AWS = require('aws-sdk');
var dynamodb = new AWS.DynamoDB();

exports.handler = (event, context, callback) => {
  console.log('add to database');
  var tableName = 'User dynamodb TABLE' // or set dynamic via process.env
  var userID = event.request.userAttributes.sub;

  dynamodb.putItem(   {
      TableName: tableName,
      Item: {
        id: {S: userID},
      },
    },
    function(err, data) {
      if (err) {
        console.log(err, err.stack); // an error occurred
        callback(err, null);
      } else {
        callback(null, data);
      }
    },
  );
};

In the cloudformation-template.json of your function (in amplify > backend > function) add this statement to lambdaexecutionpolicy area:

{
                            "Effect": "Allow",
                            "Action": [
                                "dynamodb:PutItem"
                            ],
                            "Resource": {
                                "Fn::Sub": [
                                    "arn:aws:dynamodb:${region}:${account}:table/*",
                                    {
                                        "region": {
                                            "Ref": "AWS::Region"
                                        },
                                        "account": {
                                            "Ref": "AWS::AccountId"
                                        }
                                    }
                                ]
                            }
                        }

@elgutierrez Let me know if you're still stuck after @rpostulart response.

@kaustavghosh06

I only face a problem now with this lambda function which I didn't had before, has there been a change which impacted this lambda. Error:

Invalid lambda function output : Invalid JSON (Service: AWSCognitoIdentityProviderService; Status Code: 400; Error Code: InvalidLambdaResponseException; Request ID: cfa3a834-1ea2-4948-bf31-42a08cbeae1d)

@kaustavghosh06 Yes, but now I have the same issue as @rpostulart. What are we supposed to return as result of the lambda function?

@rpostulart Hey, just to let you know that I found the solution for this issue. You should call a method at the end of the lambda execution:

exports.handler = (event, context, callback) => {
  ...
  context.done(null, event)
};

I tested this in the putItem function that didn't work of course. Thx. Success!

Was this page helpful?
0 / 5 - 0 ratings