DynamoDB en Lambda Function a través de la directiva @function en Amplify AWS

Son muchas las veces que podemos hacer las cosas de una forma u otra. Cuando estamos trabajando con DynamoDB dentro de Amplify puede pasar esto fácilmente.

Imagina que tienes que hacer una operación compleja de base de datos con DynamoDB a través de Amplify AWS, por ejemplo crear un blog, con 10 Posts y 5 comentarios. Si tienes experiencia en Amplify AWS sabrás que lo que deberás hacer en este caso es lo siguiente:


    1. Crear una operación con GraphQL para crear el Blog y así obtener el ID para relacionarlo posteriormente.
    2. Crear un Custom Resolver para ejecutar una operación Batch con GraphQL que permita insertar los 10 Posts en una única operación.
    3. Crear otro Custom Resolver para ejecutar otra operación Batch con GraphQL que permita insertar los 5 Comentarios en una única operación.

Todo eso significa que deberás gastar mucho tiempo en crear esos resolutores y ejecutar esa lógica satisfactoriamente, algo que sin duda no está mal, pero siempre existen alternativas, y aquí vamos a ver una muy directa.

DynamoDB al rescate a través de la directiva @function en Amplify AWS

Para acelerar ese proceso haciendo las cosas igual de bien podemos crear una Mutation con GraphQL que ejecute una Lambda Function haciendo uso de la directiva @function de Amplify AWS de la siguiente forma:

type Blog @model
{
  id: ID!
  name: String!
  description: String
  posts: [Post!]! @connection(name: "BlogPosts")
}

type Post @model
{
  id: ID!
  owner: String
  title: String!
  body: String!
  postBlogId: String
  blog: Blog! @connection(name: "BlogPosts")
  comments: [Comment!]! @connection(name: "PostComments", sortField: "createdAt")
  createdAt: AWSDateTime!
  updatedAt: AWSDateTime
}

type Comment @model
{
  id: ID!
  owner: String!
  comment: String!
  commentPostId: String
  post: Post! @connection(name: "PostComments")
  createdAt: AWSDateTime!
}

input CreateBlogInput {
  id: ID
  name: String!
  description: String,
  posts: [Post]
  comments: [Comment]
}

type Mutation {
  createBlogWithJS(blog: CreateBlogInput): String @function(name: "amplifyGraphqlDynamoDB-${env}")
}

Fíjate en que lo que realmente estamos haciendo es crear una función llamada amplifyGraphqlDynamoDB, así que eso es lo que deberíamos hacer ahora, crear la función amplifyGraphqlDynamoDB con el comando amplify:

amplify add function


Una vez creada nuestra función amplifyGraphqlDynamoDB vamos a abrir el archivo amplify/backend/function/amplifyGraphqlDynamoDB/amplifyGraphqlDynamoDB-cloudformation-template.json y vamos a añadir lo siguiente dentro del array de la clave Resources.AmplifyResourcesPolicy.Properties.PolicyDocument.Statement:

{
   "Effect": "Allow",
   "Action": [
      "dynamodb:BatchWrite*",
      "dynamodb:PutItem"
   ],
   "Resource": "*"
}

Con eso lo que le estamos diciendo a Amplify es que desde nuestra Lambda Function queremos utilizar DynamoDB para realizar las operaciones BatchWrite y PutItem, así podremos ejecutar operaciones Batch e inserts simples.

Ahora vamos a instalar las dependencias necesarias para nuestra Lambda Function, para ello debemos entrar al directorio amplify/backend/function/amplifyGraphqlDynamoDB/src y ejecutar los siguientes comandos:

npm install --save uuidv4 aws-sdk

Con lo anterior ya tenemos disponible el SDK de AWS y la función uuid, la primera para poder utilizar DynamoDB y la segunda para crear IDS para nuestros modelos de DynamoDB.

Ahora vamos a abrir el archivo index.js de nuestra función y vamos a añadir lo siguiente, lo cual nos permitirá realizar todas las operaciones de insert en un único proceso:

const AWS = require('aws-sdk');
const uuid = require('uuidv4').default;
const environment = process.env.ENV;
const region = process.env.REGION;
const AppSyncId = process.env.API_VUEJSAMPLIFYAVANZADO_GRAPHQLAPIIDOUTPUT;
const tablesSuffix = `${AppSyncId}-${environment}`;
const BlogTableName = `Blog-${tablesSuffix}`;
const PostTableName = `Post-${tablesSuffix}`;
const CommentTableName = `Comment-${tablesSuffix}`;
const docClient = new AWS.DynamoDB.DocumentClient({region});

exports.handler = function (event, context, callback) {
  const blogInput = event.arguments;
  const blog = {
    id: uuid(),
    __typename: "Blog",
    name: blogInput.name,
    description: blogInput.description,
    createdAt: new Date().toISOString()
  };

  const blogParams = {
    TableName: BlogTableName,
    Item: blog
  };

  docClient.put(blogParams, function(err, data) {
    if (err) {
      callback(err)
    } else {
      const post = {
        id: uuid(),
        __typename: "Post",
        title: blogInput.posts[0].title,
        body: blogInput.posts[0].body,
        createdAt: new Date().toISOString()
      };
      const postParams = {
        TableName: PostTableName,
        Item: post
      };
      docClient.put(postParams, function(err, data) {
        if (err) {
          callback(err);
        } else {
          let comments = [];
          blogInput.comments.forEach(comment => {
            comments.push({
              PutRequest: {
                Item: {
                  id: uuid(),
                  commentPostId: post.id,
                  __typename: "Comment",
                  comment,
                  createdAt: new Date().toISOString()
                }
              }
            });
          });
          const params = {
            RequestItems: {
              [CommentTableName]: comments
            }
          };
          docClient.batchWrite(params, function(err, data) {
            if (err) {
              callback(err)
            } else {
              callback(null, data)
            }
          });
         }
       });
     }
  });
};

¡Y eso es todo! Ahora simplemente deberás ejecutar el comando amplify push y a continuación ejecutar la mutación de la misma forma en la que lo hacemos siempre a través de Vuejs pasándole los datos que hemos definido.

Cursosdesarrolloweb ©. Todos los derechos reservados.

Login