서버 및 NodeJS가 없는 DynamoDB CRUD 사용

소개하다.


본고에서 DynamoDB, AWS Serverless, NodeJS를 사용하여 CRUD 프로그램을 만드는 방법을 볼 수 있습니다. DynamoDB GetItem, PutItem, UpdateItem, DeleteItem 등 모든 CRUD 작업을 소개하고 표의 모든 항목을 열거할 것입니다.모든 것은 AWS 서버 없는 프레임워크를 사용하여NodeJS에서 완성될 것입니다. 이 시리즈의 첫 번째 부분입니다. 두 번째 부분에서 이 프로그램에 인증을 추가할 것입니다. 지금부터 시작하겠습니다.

프로젝트 설정


우리의 프로젝트 폴더 구조는 다음과 같다

이 폴더들이 무엇을 하고 있는지 토론해 봅시다.
config - 이 폴더는 설정과 관련된 모든 파일을 저장합니다. 예를 들어 이 폴더는 파일을 저장합니다. 이 파일은 DynamoDB AWS SDK 실례를 만들어서 프로젝트의 어느 곳에서든 사용할 수 있도록 합니다. 따라서 파일마다 DynamoDB 실례를 가져오는 것이 아니라 파일에서 가져오고 이 파일에서 실례를 내보낸 다음 다른 곳에서 가져옵니다.
함수 - 유틸리티 함수와 관련된 모든 파일을 저장합니다.
post - CRUD 작업의 모든 lambda 함수를 저장하는 홈 폴더입니다.

서버가 없습니다.yml 파일


이 파일은 모든 서버 프로젝트의 영혼과 핵심입니다. 이 파일이 우리에게 어떤 모습인지 한번 봅시다.
service: dynamodb-crud-api

provider:
  name: aws
  runtime: nodejs12.x
  environment:
    DYNAMO_TABLE_NAME: PostsTable
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMO_TABLE_NAME}"
여기서 우리는 환경 변수를 정의했다. 다이나마이트 테이블의 이름을 저장하고, 다른 권한을 추가했다. lambda 함수는 이 권한을 가지고 서로 다른 작업을 수행해야 한다. 예를 들어 dynamodb:GetItem 테이블에서 데이터 항목을 가져오고, dynamodb:PutItem 테이블에 새 항목을 삽입하는 등이다.

익명 함수


현재 우리는 모든 lambda 함수와 각자의 설정을 정의할 것이다
functions:
  listPosts:
    handler: post/list.listPosts
    events:
      - http:
          path: posts/list
          method: get
          cors: true

  createPost:
    handler: post/create.createPost
    events:
      - http:
          path: post/create
          method: post
          cors: true

  getPost:
    handler: post/get.getPost
    events:
      - http:
          path: post/{id}
          method: get
          cors: true

  updatePost:
    handler: post/update.updatePost
    events:
      - http:
          path: post/update
          method: patch
          cors: true

  deletePost:
    handler: post/delete.deletePost
    events:
      - http:
          path: post/delete
          method: delete
          cors: true
현재, 우리는 모든 lambda 함수를 정의했습니다. API 게이트웨이 URL에 요청을 보낼 때, 이 함수를 호출합니다. 모든 lambda 함수는 API 게이트웨이를 통해 호출할 수 있도록 HTTP 이벤트를 첨부합니다.
path - 이것은 우리가 사용하고자 하는 단점의 상대적인 경로입니다. 따라서 예를 들어 API 인터페이스 URL이 https://abc.com 이면 이 단점 https://abc.com/post/{id} 호출 getPost lambda 함수를 사용합니다.
메서드 - API 요청 유형인 POST, GET, DELETE 등입니다.

DynamoDB 테이블 정의


DynamoDB를 사용하기 전에 AWS DynamoDB Pricing Model 당신이 쓰고 싶은 돈만 쓸 수 있도록 확인하십시오.
마지막으로 DynamoDB 테이블과 구성을 정의해야 합니다.
resources:
  Resources:
    UsersDynamoDbTable:
      Type: AWS::DynamoDB::Table
      DeletionPolicy: Retain
      Properties:
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S
        KeySchema:
          - AttributeName: id
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: ${self:provider.environment.DYNAMO_TABLE_NAME}
AttributeDefinitions – 테이블과 색인에 대한 모든 키 필드를 정의합니다.
KeySchema – 여기서 AttributeDefinitions에 정의된 모든 필드를 키 필드, 정렬 키 또는 파티션 키로 설정합니다.
ProvisionedThroughput – DynamoDB 테이블의 읽기와 쓰기 용량 단원 수를 정의합니다.

서버가 전혀 없습니다.yml 파일


service: dynamodb-crud-api

provider:
  name: aws
  runtime: nodejs12.x
  environment:
    DYNAMO_TABLE_NAME: PostsTable
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMO_TABLE_NAME}"

functions:
  listPosts:
    handler: post/list.listPosts
    events:
      - http:
          path: posts/list
          method: get
          cors: true

  createPost:
    handler: post/create.createPost
    events:
      - http:
          path: post/create
          method: post
          cors: true

  getPost:
    handler: post/get.getPost
    events:
      - http:
          path: post/{id}
          method: get
          cors: true

  updatePost:
    handler: post/update.updatePost
    events:
      - http:
          path: post/update
          method: patch
          cors: true

  deletePost:
    handler: post/delete.deletePost
    events:
      - http:
          path: post/delete
          method: delete
          cors: true

resources:
  Resources:
    UsersDynamoDbTable:
      Type: AWS::DynamoDB::Table
      DeletionPolicy: Retain
      Properties:
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S
        KeySchema:
          - AttributeName: id
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: ${self:provider.environment.DYNAMO_TABLE_NAME}

프로파일


이 프로필은 프로젝트의 config라는 폴더에 위치합니다. 위의 프로젝트 구조도에서 보듯이, 이 파일에는 코드의 다른 부분에서 DynamoDB API를 호출할 수 있도록 DynamoDB AWS SDK 실례를 내보내는 코드가 포함되어 있습니다.
const AWS = require("aws-sdk");

const dynamo = new AWS.DynamoDB.DocumentClient();

module.exports = dynamo;

함수 파일


이 프로젝트에서, 우리는 프로젝트에서 여러 번 사용할 모든 실용 프로그램/일반 함수를 포함하는 파일을 사용합니다.
  const sendResponse = (statusCode, body) => {
  const response = {
    statusCode: statusCode,
    body: JSON.stringify(body),
    headers: {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Credentials': true
    }
  }
  return response
}

module.exports = {
  sendResponse
};

우리는 많은 곳에서 이 함수sendResponse를 호출할 것이다. 실제로는 우리의 모든 lambda 함수에서 요청한 응답을 되돌려준다. 이것은 JSON 응답을 사용자에게 되돌려줄 것이다. 이것은 두 가지 인자가 있는데 하나는 HTTP 상태 코드이고 다른 하나는 JSON 주체이다. 우리는 이 함수를 호출할 때 그것을 전달할 것이다.우리는 또한 응답을 통해 가장 흔히 볼 수 있는 '접근 불가'cors 문제를 처리하는 데 필요한 헤더를 전달할 것입니다.

익명 함수


이제 lambda 함수를 연구할 때가 되었습니다. 이것은 우리의 모든 논리를 저장할 것입니다. 우리는 네 개의 서로 다른 CRUD 작업에 네 개의 lambda 함수를 구분할 것입니다.

DynamoDB PutItem(삽입)


이 lambda 함수는create에서 정의된 것입니다.js 파일, 이 lambda 함수에서 우리가 할 첫 번째 작업은 테이블에 새로운 데이터 항목을 삽입해서 몇 부분으로 분해하는 것입니다.
const dynamoDb = require("../config/dynamoDb");
const { sendResponse } = require("../functions/index");
const uuidv1 = require("uuid/v1");
앞에서 만든 프로필 sendReponse 함수에서 DynamoDB 실례를 가져와야 합니다. uuid 이라는 NPM을 사용하여 무작위 id를 만들고 있습니다. 이 id는 모든 게시물의 섹션 키로 사용됩니다.
  const body = JSON.parse(event.body);
  try {
    const { postTitle, postBody, imgUrl, tags } = body;
    const id = uuidv1();
    const TableName = process.env.DYNAMO_TABLE_NAME;
    const params = {
      TableName,
      Item: {
        id,
        postTitle,
        postBody,
        imgUrl,
        tags
      },
      ConditionExpression: "attribute_not_exists(id)"
    };
여기에서 요청 부하에서 서로 다른 속성을 얻을 것입니다.post표에 이 속성을 삽입한 다음 호출 uuid 라이브러리에서 제공하는 함수를 통해 무작위 id를 생성합니다.
속성 not exists - 기본적으로 동일한 Zone 키를 사용하여 데이터를 삽입하려고 하면 DynamoDB PutItem은 모든 항목의 내용을 덮어쓰지만 그러기를 원하지 않습니다. 따라서 Zone 키를 찾을 수 없을 때만 데이터를 삽입합니다. 이 조건 표현식을 사용합니다.
await dynamoDb.put(params).promise();
return sendResponse(200, { message: 'Post created successfully' })
DynamoDB put API 호출 이전 단계에서 생성된 매개 변수를 전달하고 200개의 상태 코드와 관련 메시지를 보내고 있습니다.

전체적 창조.js 파일
"use strict";

const dynamoDb = require("../config/dynamoDb");
const { sendResponse } = require("../functions/index");
const uuidv1 = require("uuid/v1");

module.exports.createPost = async event => {
  const body = JSON.parse(event.body);
  try {
    const { postTitle, postBody, imgUrl, tags } = body;
    const id = uuidv1();
    const TableName = process.env.DYNAMO_TABLE_NAME;
    const params = {
      TableName,
      Item: {
        id,
        postTitle,
        postBody,
        imgUrl,
        tags
      },
      ConditionExpression: "attribute_not_exists(id)"
    };
    await dynamoDb.put(params).promise();
    return sendResponse(200, { message: 'Post created successfully' })
  } catch (e) {
    return sendResponse(500, { message: 'Could not create the post' });
  }
};

DynamoDB GetItem(읽음)


이 lambda 함수는 get에서 정의합니다.js 파일, 읽기 동작을 실행합니다. 이것은 섹션 키를 사용하여 다이나믹 DB에서 데이터를 가져오는 것을 의미합니다.
const { id } = event.pathParameters;
const params = {
TableName: process.env.DYNAMO_TABLE_NAME,
KeyConditionExpression: "id = :id",
ExpressionAttributeValues: {
  ":id": id
  },
 Select: "ALL_ATTRIBUTES"
 };
요청한 매개 변수에서 id를 가져와 테이블의 섹션 키와 일치하게 하고 테이블에서 모든 필드를 선택합니다.
const data = await dynamoDb.query(params).promise();
if (data.Count > 0) {
  return sendResponse(200, { item: data.Items });
} else {
  return sendResponse(404, { message: "Post not found" });
}
현재 우리는 매개 변수 조회표를 사용하여 되돌아오는 항목이 있는지 확인하고, 찾은 항목이 있다면, 항목의 그룹을 되돌려줍니다. 그렇지 않으면 적당한 정보를 되돌려줍니다.

전력투구하다.js 파일
"use strict";

const { sendResponse } = require("../functions/index");
const dynamoDb = require("../config/dynamoDb");

module.exports.getPost = async event => {
  try {
    const { id } = event.pathParameters;
    const params = {
      TableName: process.env.DYNAMO_TABLE_NAME,
      KeyConditionExpression: "id = :id",
      ExpressionAttributeValues: {
        ":id": id
      },
      Select: "ALL_ATTRIBUTES"
    };

    const data = await dynamoDb.query(params).promise();
    if (data.Count > 0) {
      return sendResponse(200, { item: data.Items });
    } else {
      return sendResponse(404, { message: "Post not found" });
    }
  } catch (e) {
    return sendResponse(500, { message: "Could not get the post" });
  }
};

DynamoDB UpdateItem(업데이트)


이 lambda는 업데이트에서 정의되었습니다.js 파일, 이 lambda 함수에서 DynamoDB 테이블의 데이터를 업데이트하는 업데이트 작업을 수행할 것입니다.
    const body = JSON.parse(event.body);

    const { postTitle, postBody, imgUrl, tags, id } = body
    const params = {
      TableName: process.env.DYNAMO_TABLE_NAME,
      Key: {
        id
      },
      ExpressionAttributeValues: {
        ":postTitle": postTitle,
        ":postBody": postBody,
        ":imgUrl": imgUrl,
        ":tags": tags
      },
      UpdateExpression:
        "SET postTitle = :postTitle, postBody = :postBody, imgUrl = :imgUrl, tags = :tags",
      ReturnValues: "ALL_NEW"
    };
요청 부하에서 데이터를 얻었습니다. 요청과 함께 보내야 할 또 다른 속성은 id 업데이트할 항목입니다.
ExpressionAttributeValues – DynamoDB에는 많은 보존 키워드가 있기 때문에 테이블 필드 이름이 보존 키워드와 일치하는 경우가 있을 수 있습니다. 이 경우 이 업데이트는 오류를 던집니다.이러한 상황을 피하기 위해 DynamoDB에는 시스템이 있습니다. 이 목적을 위해 임시로 대체 이름으로 원시 필드 이름을 설정할 수 있기 때문에 이 대상의 모든 필드 값을 설정하고 있습니다.
UpdateExpression - DynamoDB의 모든 항목을 업데이트하려면 필드 이름을 해당하는 업데이트 표현식과 함께 전달해야 합니다.
ReturnValues – 업데이트 작업을 실행할 때 응답해야 하는 업데이트 필드 데이터만 나타냅니다.
    const data = await dynamoDb.update(params).promise();
    if (data.Attributes) {
      return sendResponse(200, data.Attributes);
    } else {
      return sendResponse(404, { message: "Updated post data not found" });
    }
현재 우리는 파라미터가 있는 업데이트 API를 호출하기만 하면, 업데이트된 속성 데이터가 되돌아오는지 확인해야 한다. 만약 그렇다면, 우리는 이 데이터를 되돌려줄 것이다. 그렇지 않으면 우리는 404 상태 코드와 메시지를 되돌려줄 것이다.

모두 업데이트합니다.js 파일
"use strict";

const { sendResponse } = require("../functions/index");
const dynamoDb = require("../config/dynamoDb");

module.exports.updatePost = async event => {
  try {
    const body = JSON.parse(event.body);

    const { postTitle, postBody, imgUrl, tags, id } = body
    const params = {
      TableName: process.env.DYNAMO_TABLE_NAME,
      Key: {
        id
      },
      ExpressionAttributeValues: {
        ":postTitle": postTitle,
        ":postBody": postBody,
        ":imgUrl": imgUrl,
        ":tags": tags
      },
      UpdateExpression:
        "SET postTitle = :postTitle, postBody = :postBody, imgUrl = :imgUrl, tags = :tags",
      ReturnValues: "ALL_NEW"
    };

    const data = await dynamoDb.update(params).promise();
    if (data.Attributes) {
      return sendResponse(200, data.Attributes);
    } else {
      return sendResponse(404, { message: "Updated post data not found" });
    }
  } catch (e) {
    return sendResponse(500, { message: "Could not update this post" });
  }
};

DynamoDB DeleteItem(삭제)


이 lambda 함수는 삭제 상태입니다.js 파일, 이 lambda 함수에서 테이블에서 하나를 삭제합니다.
"use strict";

const { sendResponse } = require("../functions/index");
const dynamoDb = require("../config/dynamoDb");

module.exports.deletePost = async event => {
  try {
    const body = JSON.parse(event.body);
    const { id } = body;
    const params = {
      TableName: process.env.DYNAMO_TABLE_NAME,
      Key: {
        id
      }
    };
    await dynamoDb.delete(params).promise();
    return sendResponse(200, { message: "Post deleted successfully" });
  } catch (e) {
    return sendResponse(500, { message: "Could not delete the post" });
  }
};

이 lambda 함수는 요청에서 삭제할 항목 id 만 가져오고 DynamoDB delete API에서 매개 변수로 전달합니다.
현재 우리는 기본적으로 창설/읽기/업데이트/삭제 네 가지 작업을 완성했지만, 우리는 여전히 부족한 것이 있습니다. 모든 댓글을 열거할 lambda 함수가 없습니다. 이 점을 어떻게 하는지 봅시다.

DynamoDB 검색


DynamoDB 스캔을 사용하여 표의 모든 항목을 얻을 것입니다. DynamoDB를 사용할 때 스캔 작업이 비싸질 수 있기 때문에 조심스럽게 사용해야 합니다. 사용하지 않도록 해야 합니다. 설령 우리가 그것을 사용해야 한다고 해도 프로젝트에 대한 불필요한 스캔이 아니라 필요한 데이터만 가져와야 합니다.
"use strict";

const dynamoDb = require("../config/dynamoDb");
const { sendResponse } = require("../functions/index");

module.exports.listPosts = async event => {
  try {
    const params = {
      TableName: process.env.DYNAMO_TABLE_NAME,
    }
    const posts = await dynamoDb.scan(params).promise();
    return sendResponse(200, { items: posts.Items });
  } catch (e) {
    return sendResponse(500, { message: "Could not get the posts list" });
  }
};

이 함수는 목록에 있습니다.js 파일, 우리는 여기에서 아주 간단한 다이나마이트 DB 스캔을 하고 데이터를 되돌려줍니다.

결론


이것은 아주 긴 댓글이지만, 만약 당신이 이 점을 달성할 수 있다면 축하합니다. 왜냐하면 당신은 현재 완전한 CRUD API를 가지고 있기 때문입니다. DynamoDB, AWS Serverless, Nodejs를 사용하여 제작하고 있기 때문입니다. 우리는 이 프로그램을 수시로 강화하고 더욱 좋게 할 수 있습니다. 다음은 몇 가지 생각입니다.
  • 애플리케이션에 인증을 추가합니다.
  • 사용자 기반 게시를 추가합니다.
  • 유효성 검사를 추가합니다.
  • 비용 절감
  • 성능 향상 및 비용 절감을 위해 DynamoDB Global Secondary Index 추가
  • 다른 제안이 있으면 언제든지 아래 댓글에 추가해 주십시오. 이 프로그램은 더 많은 부분을 가지고 있으니 기대해 주십시오.

    이 코드 가져오기


    Source code on Github
    자세히 보기:
    How to extract text from an image using AWS Serverless
    AI-based image identification using AWS Serverless
    DynamoDB VS MongoDB
    게시물CRUD with DynamoDB using Serverless and NodeJS이 가장 먼저DevsWisdom에 올라왔다.

    좋은 웹페이지 즐겨찾기