정보실

웹학교

정보실

기타 서버리스 기술을 사용하여 완벽한 백엔드 시스템을 구축하는 방법

본문

서버 리스로 완전한 백엔드 시스템을 구축하는 방법


이 기사에서는 애플리케이션의 백엔드를 빌드하는 데 필요한 모든 것을 빌드하고 배치하는 방법을 설명합니다. 

우리는 AWS를 사용하여 이 모든 것을 호스트하고 Serverless Framework를 사용하여 모두 배포 할 것입니다.


https://www.freecodecamp.org/news/complete-back-end-system-with-serverless/ 


이 기사가 끝나면 다음과 같은 방법을 알게 됩니다.

  • 서버리스 프레임 워크와 함께 작동하도록 AWS 계정 설정
  • 서버리스 프로젝트 설정 및 Lambda 배포
  • S3 버킷으로 프라이빗 클라우드 스토리지 생성 및 컴퓨터에서 파일 업로드
  • API Gateway 및 AWS Lambda를 사용하여 API 배포
  • AWS DynamoDB로 서버리스 데이터베이스 테이블 생성
  • DynamoDB 테이블에서 데이터를 가져 오는 API 생성
  • DynamoDB 테이블에 데이터를 추가하기 위한 API 생성
  • 파일을 저장하고 S3 버킷에서 파일을 가져 오는 API 생성
  • API 키로 모든 API 엔드 포인트 보안

이러한 모든 작업을 수행 할 수 있으면 대부분의 응용 프로그램 백엔드에서 필요한 모든 기능을 만들 수 있습니다.


AWS를 통한 서버리스 설정 


Serverless Framework는 개발자가 컴퓨터에서 서비스를 구성하고 배포하는 데 사용할 수 있는 도구입니다. 

이 모든 것이 함께 작동 할 수 있도록 약간의 설정이 있으며 이 섹션에서는 이를 수행하는 방법을 보여줍니다.


서버리스가 귀하의 계정에서 작업 할 수 있게 하려면 사용자를 설정해야 합니다. 이렇게 하려면 AWS로 이동하여 "IAM"(Identity and Access Management)을 검색하십시오.


IAM 페이지에서 왼쪽의 목록에서 사용자를 클릭하십시오. 계정의 사용자 목록이 열립니다. 여기에서 사용자 추가를 클릭합니다.


프로그래밍 방식으로 액세스 할 수 있는 사용자를 만들어야 하며 사용자를 ServerlessAccount라고 했지만 이름은 중요하지 않습니다.


createUser-1.png 


다음으로 사용자에게 몇 가지 권한을 부여해야 합니다. 권한 화면에서 기존 정책을 직접 첨부를 선택한 다음 관리자 액세스를 선택하십시오. 이렇게 하면 필요한 모든 리소스를 만들 수 있는 Serverless Framework 권한이 부여됩니다.


태그를 추가 할 필요가 없으므로 검토로 바로 이동할 수 있습니다.


credential.png 


검토 창에서 사용자에게 액세스 키 ID와 비밀 액세스 키가 제공되었음을 알 수 있습니다. 다음 부분에 필요한 내용이 필요하므로 이 페이지를 열어 두십시오.


서버리스 설치 및 구성 


이제 사용자를 만들었으므로 서버에 Serverless Framework를 설치해야 합니다.


터미널을 열고 이 명령을 실행하여 컴퓨터에 서버리스를 전체적으로 설치하십시오. NodeJS가 설치되어 있지 않으면 이 페이지를 확인하십시오.

npm install -g serverless

이제 서버리스가 설치되었으므로 서버리스가 사용할 자격 증명을 설정해야 합니다. 액세스 키 ID와 비밀 액세스 키를 올바른 위치에 두고 이 명령을 실행하십시오.


serverless config credentials --provider aws --key ${Your access key ID} --secret ${Your secret access key} --profile serverlessUser

이것이 실행되면, 당신은 모두 서버리스로 설정됩니다.



첫 AWS Lambda 배포 


serverlessUser를 설정하지 않으면 Serverless Framework를 사용하여 무언가를 배포하려고 합니다. 서버리스 템플릿을 사용하여 배포 할 수 있는 기본 프로젝트를 설정할 수 있습니다. 이것이 이 서버리스 프로젝트 전체의 기반이 될 것입니다.



터미널에서 템플릿을 사용하여 서버리스 프로젝트를 만들 수 있습니다. 이 명령은 myServerlessProject 폴더에 NodeJS Serverless 프로젝트를 작성합니다.


serverless create --template aws-nodejs --path myServerlessProject

코드 편집기에서 폴더를 열면 생성 한 것을 볼 수 있습니다.


folderStruct.png 


우리는 handler.js와 serverless.yml이라는 두 가지 파일을 가지고 있습니다.


handler.js 


이 파일은 Lambda 함수로 AWS 계정에 업로드 되는 함수입니다. Lambda 함수는 훌륭하며 나중에 시리즈에서 더 많이 사용할 것입니다.


serverless.yml 


이것은 우리에게 매우 중요한 파일입니다. 이것이 우리 배치의 모든 구성이 진행되는 곳입니다. 사용할 런타임, 배포 할 계정 및 배포 대상을 서버리스에 알려줍니다.


배포가 제대로 작동하려면 이 파일을 변경해야 합니다. 제공자 객체에서 새로운 프로파일 라인 serverlessUser를 추가해야 합니다. 이는 서버리스에게 마지막 섹션에서 생성 한 AWS 자격 증명을 사용하도록 지시합니다.


함수로 스크롤하여 hello라고 하는 하나의 함수가 있고 handler.js 파일 내의 함수를 가리키는 것을 볼 수 있습니다. 이는 이 Lambda 함수를 이 프로젝트의 일부로 배포 할 것임을 의미합니다.


이 기사의 뒷부분에서 이 serverless.yml 파일에 대해 더 많이 배울 것입니다.


프로젝트 배포 


이제 첫 번째 배포를 수행 할 때까지 파일을 살펴 보았습니다. 터미널을 열고 프로젝트 폴더로 이동하십시오. 입력하는 것만 큼 간단하게 배포 할 수 있습니다.


serverless deploy

시간이 걸리지 만 완료되면 모든 것이 성공적으로 배포되었는지 확인할 수 있습니다.


브라우저를 열고 AWS 계정으로 이동하십시오. Lambda를 검색하면 모든 Lambda 함수 목록이 표시됩니다. (아무것도 보이지 않으면 해당 지역이 N. Virginia로 설정되어 있는지 확인하십시오). 프로젝트 폴더의 handler.js 파일에 있는 정확한 코드가 포함 된 myserverlessproject-dev-hello Lambda가 표시됩니다.


S3 버킷 배포 및 파일 업로드 


이 섹션에서는 Amazon S3 버킷을 배포 한 다음 컴퓨터에서 파일을 동기화 하는 방법에 대해 알아 봅니다. 이것이 S3를 파일의 클라우드 스토리지로 사용하는 방법입니다.



serverless.yml 파일을 열고 주석 처리 된 모든 행을 제거하십시오. 파일 하단으로 스크롤하여 S3 리소스를 포함하도록 다음 코드를 추가하십시오.


resources:
    Resources:
        DemoBucketUpload:
            Type: AWS::S3::Bucket
            Properties:
                BucketName: EnterAUniqueBucketNameHere

버킷 이름을 변경하면 다시 배포 할 준비가 되었습니다. 터미널을 다시 열고 서버리스 배포를 실행하십시오. 버킷 이름이 고유하지 않다는 오류가 발생할 수 있습니다.이 경우 버킷 이름을 변경하고 파일을 저장 한 후 명령을 다시 실행해야 합니다.


성공하면 브라우저를 통해 AWS 콘솔에서 새 S3 버킷을 확인할 수 있습니다. S3를 검색하면 새로 생성 된 버킷이 표시됩니다.


파일 동기화 


버킷을 갖는 것은 좋지만 이제 버킷에 파일을 넣어야 합니다. 이를 위해 S3 Sync라는 서버리스 플러그인을 사용할 것입니다. 이 플러그인을 프로젝트에 추가하려면 플러그인을 정의해야 합니다. 공급자 객체 뒤에 다음 코드를 추가하십시오.


plugins:
    - serverless-s3-sync

이 플러그인에는 사용자 지정 구성이 필요하므로 serverless.yml 파일에 다른 필드를 추가하여 버킷 이름을 변경하십시오.


custom:
    s3Sync:
        - bucketName: YourUniqueBucketName
          localDir: UploadData

이 코드 섹션에서는 S3 Sync 플러그인이 UploadData 폴더의 내용을 버킷에 업로드하도록 지시합니다. 현재 해당 폴더가 없으므로 폴더를 만들고 파일을 추가해야 합니다. 텍스트 파일, 이미지 또는 업로드 할 항목을 추가 할 수 있습니다. 폴더에 파일이 하나 이상 있는지 확인하십시오.


마지막으로 해야 할 일은 플러그인을 설치하는 것입니다. 운 좋게도 모든 서버리스 플러그인은 npm 패키지이므로 터미널에서 npm install --save-dev serverless-s3-sync를 실행하여 설치할 수 있습니다.


이전과 마찬가지로 서버리스 배포를 실행하고 배포가 완료 될 때까지 기다릴 수 있습니다. 완료되면 브라우저와 버킷으로 돌아갈 수 있으며 프로젝트의 UploadData 폴더에 넣은 모든 파일을 볼 수 있습니다.


Screenshot-2019-12-10-at-07.12.07.png 


Lambda 및 API Gateway를 사용하여 API 생성 


이 섹션에서는 서버리스로 가장 유용한 것 중 하나 인 API 생성을 수행하는 방법을 배웁니다. API를 만들면 데이터베이스에서 데이터를 가져 오는 것, S3 스토리지, 다른 API를 치는 것 등 많은 일을 할 수 있습니다!


API를 만들려면 먼저 요청을 처리 할 새 Lambda 함수를 만들어야 합니다. Lambdas를 몇 개 만들 예정이므로 프로젝트에 공통 및 끝점이라는 두 개의 하위 폴더가 있는 lambdas 폴더를 만들 것입니다.


Screenshot-2019-12-10-at-07.47.27.png 


엔드 포인트 폴더 안에 getUser.js라는 새 파일을 추가 할 수 있습니다. 이 API는 누군가가 사용자의 ID를 기반으로 요청하고 데이터를 가져올 수 있도록 합니다. 이것은 API 코드입니다.


const Responses = require('../common/API_Responses');

exports.handler = async event => {
    console.log('event', event);

    if (!event.pathParameters || !event.pathParameters.ID) {
        // failed without an ID
        return Responses._400({ message: 'missing the ID from the path' });
    }

    let ID = event.pathParameters.ID;

    if (data[ID]) {
        // return the data
        return Responses._200(data[ID]);
    }

    //failed as ID not in the data
    return Responses._400({ message: 'no ID in data' });
};

const data = {
    1234: { name: 'Anna Jones', age: 25, job: 'journalist' },
    7893: { name: 'Chris Smith', age: 52, job: 'teacher' },
    5132: { name: 'Tom Hague', age: 23, job: 'plasterer' },
};

요청에 ID가 없으면 실패한 응답을 반환합니다. 해당 ID에 대한 데이터가 있으면 해당 데이터를 반환합니다. 해당 사용자 ID에 대한 데이터가 없으면 실패 응답도 반환합니다.


아시다시피 API_Responses의 Responses 객체가 필요합니다. 이러한 응답은 우리가 만드는 모든 API에 공통적이므로 이 코드를 가져 오기 가능하게 만드는 것은 현명한 조치입니다. 공통 폴더에 API_Responses.js라는 새 파일을 작성하고 다음 코드를 추가하십시오.


const Responses = {
    _200(data = {}) {
        return {
            headers: {
                'Content-Type': 'application/json',
                'Access-Control-Allow-Methods': '*',
                'Access-Control-Allow-Origin': '*',
            },
            statusCode: 200,
            body: JSON.stringify(data),
        };
    },

    _400(data = {}) {
        return {
            headers: {
                'Content-Type': 'application/json',
                'Access-Control-Allow-Methods': '*',
                'Access-Control-Allow-Origin': '*',
            },
            statusCode: 400,
            body: JSON.stringify(data),
        };
    },
};

module.exports = Responses;

이 함수 세트는 API 게이트웨이와 함께 Lambda를 사용할 때 필요한 올바른 응답 작성을 단순화하는 데 사용됩니다 (초 단위로 수행함). 메소드는 헤더, 상태 코드를 추가하고 리턴해야 하는 데이터를 문자열화 합니다.


API 용 코드가 준비되었으므로 serverless.yml 파일에서 설정해야 합니다. serverless.yml 파일의 기능 섹션으로 스크롤 하십시오. 이 가이드의 마지막 부분에서는 hello 함수를 배포했지만 더 이상 필요하지 않습니다. 함수 객체를 삭제하고 다음과 같이 바꾸십시오 :


functions:
    getUser:
        handler: lambdas/endpoints/getUser.handler
        events:
            - http:
                  path: get-user/{ID}
                  method: GET
                  cors: true

이 코드는 핸들러 메소드의 lambdas / getUser 파일에있는 getUser라는 새 Lambda 함수를 작성합니다. 그런 다음이 람다 함수가 실행되도록 트리거 할 수 있는 이벤트를 정의합니다.


Lambda를 API로 만들기 위해 http 이벤트를 추가 할 수 있습니다. 이는 서버리스에게 이 계정에 API 게이트웨이를 추가하도록 지시 한 다음 경로를 사용하여 API 엔드 포인트를 정의 할 수 있습니다. 이 경우 get-user / {ID}는 URL이 https : // $ {something-provided-by-API-Gateway} / get-user / {ID}이며, 여기서 ID는 Lambda에 경로 매개 변수. 또한 원하는 경우 프런트 엔드 애플리케이션에서 이 엔드 포인트에 액세스 할 수 있도록 메소드를 GET으로 설정하고 CORS를 사용하도록 설정하십시오.


이제 다시 배포 할 수 있으며 이번에는 단축 명령 sls deploy를 사용할 수 있습니다. 이렇게 하면 몇 자만 절약 할 수 있지만 많은 오타를 피할 수 있습니다. 이 작업이 완료되면 엔드 포인트 목록도 포함 된 출력이 표시됩니다. 엔드 포인트를 복사하고 브라우저로 가서 테스트 해 볼 수 있습니다.


Screenshot-2019-12-10-at-07.19.00.png 


API URL을 브라우저에 붙여 넣고 5132의 끝에 ID를 추가하면 {name : 'Tom Hague', age : 23, job : 'plasterer'}의 응답을 다시 받아야 합니다. 1234와 같은 다른 ID를 입력하면 다른 데이터가 표시되지만 ID를 7890으로 입력하거나 입력하지 않으면 오류가 발생합니다.


API에 더 많은 데이터를 추가하려면 getUser.js 파일의 데이터 객체에 새 행을 추가하면 됩니다. 그런 다음 하나의 함수 sls deploy -f $ {functionName} 만 배포하는 특수 명령을 실행할 수 있습니다. 그래서 우리에게 그것은 :


sls deploy -f getUser

이제 새 데이터의 ID를 사용하여 요청하면 API는 오류 대신 해당 새 데이터를 반환합니다.


AWS에서 데이터베이스 생성 


DynamoDB는 AWS에서 완전 호스팅 된 비 관계형 데이터베이스입니다. 정기적으로 액세스하고 업데이트 해야 하는 데이터를 저장하기 위한 완벽한 솔루션입니다. 이 섹션에서는 서버리스를 사용하여 DynamoDB 테이블을 생성하는 방법에 대해 알아 봅니다.



serverless.yml 파일에서 Resources 섹션에 몇 가지 구성을 추가합니다.


resources:
    Resources:
        DemoBucketUpload:
            Type: AWS::S3::Bucket
            Properties:
                BucketName: ${self:custom.bucketName}
        # New Code
        MyDynamoDbTable:
            Type: AWS::DynamoDB::Table
            Properties:
                TableName: ${self:custom.tableName}
                AttributeDefinitions:
                    - AttributeName: ID
                      AttributeType: S
                KeySchema:
                    - AttributeName: ID
                      KeyType: HASH
                BillingMode: PAY_PER_REQUEST

이 코드에서 TableName이 $ {self : custom.tableName} 인 새 DynamoDB 테이블을 생성하고 ID 속성을 정의하고 청구 모드를 요청 당 지불하도록 설정하는 것을 볼 수 있습니다.


이것은 serverless.yml 파일에서 변수를 사용하는 첫 번째 방법입니다. 몇 가지 이유로 변수를 사용할 수 있으며 작업을 훨씬 쉽게 할 수 있습니다. 이 경우 변수 custom.tableName을 참조합니다. 그런 다음 테이블 이름을 복사하여 붙여 넣지 않고도 여러 위치에서 이 변수를 참조 할 수 있습니다. 이 작업을 수행하려면 사용자 정의 섹션에 tableName을 추가해야 합니다. 우리의 경우에는 tableName : player-points 행을 추가하여 플레이어가 가진 포인트를 저장할 테이블을 만듭니다. 이 테이블 이름은 계정마다 고유해야 합니다.


테이블을 정의 할 때 고유 식별 필드가 될 필드 중 하나 이상을 정의해야 합니다. DynamoDB는 비 관계형 데이터베이스이므로 전체 스키마를 정의 할 필요가 없습니다. 여기서는 속성 유형이 문자열이고 키 유형이 HASH임을 나타내는 ID를 정의했습니다.


정의의 마지막 부분은 청구 모드입니다. DynamoDB에 대한 지불 방법은 두 가지가 있습니다.

  • 요청 당 지불
  • 프로비저닝 된 리소스.

프로비저닝 된 리소스를 통해 테이블에서 읽고 쓸 데이터 양을 정의 할 수 있습니다. 이것의 문제는 더 많은 요청을 사용하기 시작하면 요청이 조절되며 아무도 사용하지 않아도 리소스에 대한 비용을 지불한다는 것입니다.


요청 당 지불 요청 당 지불하는 것이 훨씬 간단합니다. 이것은 당신이 그것을 사용하는 사람이 없다면 당신은 아무것도 지불하지 않고 한 번에 그것을 사용하는 수백 명의 사람들이 있다면 모든 요청이 작동한다는 것을 의미합니다. 이러한 추가 유연성을 위해 요청 당 지불에 대해 약간 더 많은 비용을 지불하지만 장기적으로는 일반적으로 더 저렴합니다.


sls deploy를 다시 실행하면 AWS 콘솔을 열고 DynamoDB를 검색 할 수 있습니다. 우리는 새로운 테이블을 볼 수 있어야 하고 거기에 아무것도 없는 것을 볼 수 있습니다.


테이블에 데이터를 추가하려면 항목 작성을 클릭하고 고유 ID를 지정하고 더하기 단추를 클릭 한 후 새 필드에 추가하고 문자열 유형을 선택하십시오. 우리는 여기에 이름의 필드와 Jess의 가치를 부여해야 합니다. 점수 필드를 12로 설정하십시오. 저장을 클릭하면 다이너 모 테이블에 데이터가 있습니다.

Screenshot-2019-12-10-at-07.57.54.png 


DynamoDB 테이블에서 데이터 가져 오기 


이제 Dynamo 테이블을 만들었으므로 테이블에 데이터를 가져와 추가 할 수 있기를 원합니다. get 엔드 포인트가 있는 테이블에서 데이터를 가져 오는 것으로 시작하겠습니다.



엔드 포인트 폴더에 getPlayerScore.js라는 새 파일을 만들 것입니다. 이 Lambda 엔드 포인트는 사용자 요청을 처리하고 Dynamo 테이블에서 해당 데이터를 가져옵니다.


const Responses = require('../common/API_Responses');
const Dynamo = require('../common/Dynamo');

const tableName = process.env.tableName;

exports.handler = async event => {
    console.log('event', event);

    if (!event.pathParameters || !event.pathParameters.ID) {
        // failed without an ID
        return Responses._400({ message: 'missing the ID from the path' });
    }

    let ID = event.pathParameters.ID;

    const user = await Dynamo.get(ID, tableName).catch(err => {
        console.log('error in Dynamo Get', err);
        return null;
    });

    if (!user) {
        return Responses._400({ message: 'Failed to get user by ID' });
    }

    return Responses._200({ user });
};

여기에 사용 된 코드는 getUser.js 파일의 코드와 매우 유사합니다. ID의 경로 매개 변수가 있는지 확인하고 사용자 데이터를 얻은 다음 사용자를 반환합니다. 가장 큰 차이점은 사용자를 얻는 방법입니다.


Dynamo 함수 객체를 가져 왔으며 Dynamo.get을 호출하고 있습니다. ID와 테이블 이름을 전달한 다음 오류가 발생합니다. 이제 공통 폴더의 Dynamo.js라는 새 파일에 해당 Dynamo 함수 객체를 생성해야 합니다.


const AWS = require('aws-sdk');

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

const Dynamo = {
    async get(ID, TableName) {
        const params = {
            TableName,
            Key: {
                ID,
            },
        };

        const data = await documentClient.get(params).promise();

        if (!data || !data.Item) {
            throw Error(`There was an error fetching the data for ID of ${ID} from ${TableName}`);
        }
        console.log(data);

        return data.Item;
    },
};
module.exports = Dynamo;

Dynamo를 읽고 쓰려면 합리적인 양의 코드가 필요합니다. Dynamo를 사용할 때마다 해당 코드를 작성할 수 있지만 프로세스를 단순화하는 기능이 훨씬 더 깨끗합니다.


파일은 먼저 AWS를 가져온 다음 DynamoDB Document Client의 인스턴스를 생성합니다. Lambda에서 Dynamo를 사용하는 가장 쉬운 방법은 문서 클라이언트입니다. 비동기 get 함수를 사용하여 Dynamo 객체를 생성합니다. 요청을 하는 데 필요한 것은 ID와 테이블 이름뿐입니다. DocumentClient에 대한 올바른 매개 변수 형식으로 형식을 지정하고 documentClient.get 요청을 기다린 후 끝에 .promise()를 추가해야 합니다. 이렇게 하면 요청이 콜백에서 처리하기 훨씬 쉬운 약속으로 바뀝니다. 우리는 Dynamo에서 아이템을 받을 수 있는지 확인한 다음 그 아이템을 반환합니다.


이제 필요한 모든 코드를 갖추었으며 serverless.yml 파일도 업데이트해야 합니다. 가장 먼저 해야 할 일은 새로운 API 엔드 포인트를 함수 목록에 추가하여 추가하는 것입니다.

getPlayerScore:
        handler: lambdas/endpoints/getPlayerScore.handler
        events:
            - http:
                  path: get-player-score/{ID}
                  method: GET
                  cors: true

엔드 포인트를 작동 시키기 위해 변경해야 할 사항이 두 가지 더 있습니다.

  • 환경 변수
  • 권한

getPlayerScore.js 파일에서 다음과 같은 코드가 있음을 알 수 있습니다.


const tableName = process.env.tableName;

여기에서 Lambda의 환경 변수에서 테이블 이름을 가져옵니다. 올바른 환경 변수를 사용하여 Lambda를 생성하려면 tableName 필드와 $ {self : custom.tableName} 값을 사용하여 environment라는 제공자에서 새 객체를 설정해야 합니다. 이를 통해 테이블을 수정하도록 요청합니다.


또한 Lambdas에 Dynamo에 액세스 할 수 있는 권한을 부여해야 합니다. 공급자에 iamRoleStatements라는 다른 필드를 추가해야 합니다. 여기에는 특정 서비스 또는 리소스에 대한 액세스를 허용하거나 금지 할 수 있는 일련의 정책이 있습니다.

provider:
    name: aws
    runtime: nodejs10.x
    profile: serverlessUser
    region: eu-west-1
    environment:
        tableName: ${self:custom.tableName}
    iamRoleStatements:
        - Effect: Allow
          Action:
              - dynamodb:*
          Resource: '*'

이 모든 것이 프로 바이더 객체에 추가되었으므로 모든 Lambdas에 적용됩니다.


이제 sls deploy를 다시 실행하여 새 엔드 포인트를 배포 할 수 있습니다. 이 작업이 완료되면 https://${something-provided-by-API-Gateway} / get-player-score / {ID}의 새 엔드 포인트로 출력을 가져와야 합니다. 해당 URL을 브라우저 탭에 복사하고 마지막 섹션에서 만든 플레이어의 ID를 추가하면 응답이 나타납니다.


Screenshot-2019-12-10-at-07.59.02.png 



DynamoDB에 새 데이터 추가 


Dynamo에서 데이터를 가져올 수 있는 것은 멋지지만 테이블에 새 데이터를 추가 할 수 없다면 쓸모가 없습니다. Dynamo 테이블에서 새 데이터를 생성하기 위해 POST 엔드 포인트를 생성 할 예정입니다.



엔드 포인트 폴더에 createPlayerScore.js라는 새 파일을 작성하고 다음 코드를 추가하여 시작하십시오.


const Responses = require('../common/API_Responses');
const Dynamo = require('../common/Dynamo');

const tableName = process.env.tableName;

exports.handler = async event => {
    console.log('event', event);

    if (!event.pathParameters || !event.pathParameters.ID) {
        // failed without an ID
        return Responses._400({ message: 'missing the ID from the path' });
    }

    let ID = event.pathParameters.ID;
    const user = JSON.parse(event.body);
    user.ID = ID;

    const newUser = await Dynamo.write(user, tableName).catch(err => {
        console.log('error in dynamo write', err);
        return null;
    });

    if (!newUser) {
        return Responses._400({ message: 'Failed to write user by ID' });
    }

    return Responses._200({ newUser });
};

이 코드는 몇 가지 변경 사항이 있는 getPlayerScore 코드와 매우 유사합니다. 요청 본문에서 사용자를 가져 와서 사용자에게 ID를 추가 한 다음 Dynamo.write 함수에 전달합니다. Lambda로 전달하기 전에 API Gateway가 이를 문자열화 할 때 이벤트 본문을 구문 분석해야 합니다.


이제 일반적인 Dynamo.js 파일을 수정하여 .write 메서드를 추가해야 합니다. 이것은 .get 함수와 매우 유사한 단계를 수행하고 새로 작성된 데이터를 리턴 합니다.

async write(data, TableName) {
        if (!data.ID) {
            throw Error('no ID on the data');
        }

        const params = {
            TableName,
            Item: data,
        };

        const res = await documentClient.put(params).promise();

        if (!res) {
            throw Error(`There was an error inserting ID of ${data.ID} in table ${TableName}`);
        }

        return data;
    }

엔드 포인트와 공통 코드를 만들었으므로 마지막으로 serverless.yml 파일을 수정해야 합니다. 마지막 섹션에서 환경 변수와 권한을 추가 했으므로 기능과 API 구성 만 추가하면 됩니다. 이 메소드는 GET 대신 POST이기 때문에 이전 두 엔드 포인트와 다릅니다.


createPlayerScore:
        handler: lambdas/endpoints/createPlayerScore.handler
        events:
            - http:
                  path: create-player-score/{ID}
                  method: POST
                  cors: true
sls deploy로 이것을 배포하면 create-player-score endpoint를 포함하여 3 개의 엔드 포인트가 생성됩니다. POST 엔드 포인트 테스트는 GET 요청보다 복잡하지만 운 좋게도 도움이 되는 도구가 있습니다. Postman을 사용하여 모든 엔드 포인트를 빠르고 쉽게 테스트 할 수 있습니다. 


새 요청을 작성하고 플레이어 레벨 점수를 붙여 넣으십시오. 요청 유형을 POST로 변경하고 URL 끝에 ID를 설정해야 합니다. POST 요청을 하고 있기 때문에 요청 본문 내에서 데이터를 보낼 수 있습니다. 본문을 클릭 한 다음 원시를 클릭하고 본문 유형으로 JSON을 선택하십시오. 그런 다음 테이블에 넣을 데이터를 추가 할 수 있습니다. 보내기를 클릭하면 성공적인 응답이 나타납니다.


postman.png 


데이터가 테이블에 추가되었는지 확인하기 위해 방금 만든 새 데이터의 ID를 사용하여 get-player-score 요청을 할 수 있습니다. Dynamo 콘솔로 이동하여 테이블의 모든 항목을 볼 수도 있습니다.


S3 GET 및 POST 엔드 포인트 생성 


Dynamo는 뛰어난 데이터베이스 스토리지 솔루션이지만 때로는 최고의 스토리지 솔루션이 아닙니다. 변경되지 않는 데이터가 있고 비용을 절약하거나 JSON 이외의 파일을 저장하려는 경우 Amazon S3를 고려할 수 있습니다.



S3에서 파일을 가져오고 생성하기 위한 엔드 포인트 생성은 DynamoDB와 매우 유사합니다. 공통 S3 파일 인 두 개의 엔드 포인트 파일을 작성하고 serverless.yml 파일을 수정해야 합니다.


S3에 파일을 추가하는 것으로 시작하겠습니다. 엔드 포인트 폴더에 createFile.js 파일을 작성하고 이 코드를 추가하십시오.


const Responses = require('../common/API_Responses');
const S3 = require('../common/S3');

const bucket = process.env.bucketName;

exports.handler = async event => {
    console.log('event', event);

    if (!event.pathParameters || !event.pathParameters.fileName) {
        // failed without an fileName
        return Responses._400({ message: 'missing the fileName from the path' });
    }

    let fileName = event.pathParameters.fileName;
    const data = JSON.parse(event.body);

    const newData = await S3.write(data, fileName, bucket).catch(err => {
        console.log('error in S3 write', err);
        return null;
    });

    if (!newData) {
        return Responses._400({ message: 'Failed to write data by filename' });
    }

    return Responses._200({ newData });
};

이 코드는 createPlayerScore.js 코드와 거의 동일하지만 ID 대신 파일 이름을 사용하고 Dynamo.write 대신 S3.write를 사용합니다.


이제 S3에 대한 요청을 단순화하기 위해 S3 공통 코드를 작성해야 합니다.


const AWS = require('aws-sdk');
const s3Client = new AWS.S3();

const S3 = {
    async write(data, fileName, bucket) {
        const params = {
            Bucket: bucket,
            Body: JSON.stringify(data),
            Key: fileName,
        };
        const newData = await s3Client.putObject(params).promise();
        if (!newData) {
            throw Error('there was an error writing the file');
        }
        return newData;
    },
};
module.exports = S3;

이 파일의 코드는 Dynamo.js의 코드와 매우 유사하지만 요청의 매개 변수와 약간의 차이가 있습니다.


S3에 쓰기 위해 마지막으로 해야 할 일은 severless.yml 파일을 변경하는 것입니다. 환경 변수 추가, 권한 추가, 함수 추가 및 S3 버킷 추가 등 네 가지 작업을 수행해야 합니다.


제공자에서 우리는 bucketName의 새로운 환경 변수 $ {self : custom.s3UploadBucket}을 추가 할 수 있습니다.


S3에 읽고 쓸 수 있는 권한을 추가하기 위해 기존 정책에 새 권한을 추가 할 수 있습니다. dynamodb : * 바로 다음에 s3 : * 줄을 추가 할 수 있습니다.


함수를 추가하는 것은 다른 모든 함수로 수행 한 것과 같습니다. 엔드 포인트 코드에서 확인 중인 경로에 fileName 매개 변수가 있는지 확인하십시오.


createFile:
        handler: lambdas/endpoints/createFile.handler
        events:
            - http:
                  path: create-file/{fileName}
                  method: POST
                  cors: true

마지막으로 이러한 파일을 업로드 할 새 버킷을 만들어야 합니다. 사용자 정의 섹션에서 새 필드 s3UploadBucket을 추가하고 고유 한 버킷 이름으로 설정해야 합니다. 또한 리소스를 구성해야 합니다. Dynamo 테이블 구성 후 파일 업로드를 위한 새 버킷을 생성하기 위해 이를 추가 할 수 있습니다.


s3UploadBucket:
            Type: AWS::S3::Bucket
            Properties:
                BucketName: ${self:custom.s3UploadBucket}

이 설정으로 다시 배포 할 차례입니다. sls deploy를 다시 실행하면 새 업로드 버킷과 S3 쓰기 엔드 포인트가 배포됩니다. 쓰기 엔드 포인트를 테스트하려면 Postman으로 돌아 가야 합니다.


서버리스가 배치를 완료했을 때 얻은 작성 파일 URL에 복사하여 Postman에 붙여 넣고 요청 유형을 POST로 변경하십시오. 다음으로 업로드 할 파일 이름을 추가해야 합니다. 우리의 경우 우리는 car.json을 업로드 할 것입니다. 마지막으로 해야 할 일은 요청에 데이터를 추가하는 것입니다. Body를 선택한 다음 JSON 유형으로 raw를 선택하십시오. 원하는 JSON 데이터를 추가 할 수 있지만 다음은 몇 가지 예제 데이터입니다.


{
	"model": "Ford Focus",
	"year": 2018,
	"colour": "red"
}

이 데이터를 게시하면 파일에 대한 ETag 참조가 포함 된 200 응답이 표시됩니다. 콘솔과 새로운 S3 버킷으로 들어가면 car.json을 볼 수 있습니다.


S3에서 데이터 가져 오기 


이제 S3에 데이터를 업로드 할 수 있으므로 다시 가져올 수 있기를 원합니다. 엔드 포인트 폴더 내에 getFile.js 파일을 작성하는 것으로 시작하십시오.

const Responses = require('../common/API_Responses');
const S3 = require('../common/S3');

const bucket = process.env.bucketName;

exports.handler = async event => {
    console.log('event', event);

    if (!event.pathParameters || !event.pathParameters.fileName) {
        // failed without an fileName
        return Responses._400({ message: 'missing the fileName from the path' });
    }

    const fileName = event.pathParameters.fileName;

    const file = await S3.get(fileName, bucket).catch(err => {
        console.log('error in S3 get', err);
        return null;
    });

    if (!file) {
        return Responses._400({ message: 'Failed to read data by filename' });
    }

    return Responses._200({ file });
};

이것은 이전에 생성 한 이전 GET 엔드 ​​포인트와 매우 유사합니다. 차이점은 fileName 경로 매개 변수 S3.get을 사용하고 파일을 리턴하는 것입니다.


일반적인 s3.js 파일 안에 get 함수를 추가해야 합니다. 이것과 Dynamo에서 얻는 것의 주요 차이점은 S3에서 가져올 때 결과는 JSON 응답이 아니라 버퍼라는 것입니다. 즉, JSON 파일을 업로드하면 JSON 형식으로 돌아 오지 않으므로 JSON 파일이 있는지 확인한 다음 다시 JSON으로 변환해야 합니다.

async get(fileName, bucket) {
        const params = {
            Bucket: bucket,
            Key: fileName,
        };
        let data = await s3Client.getObject(params).promise();
        if (!data) {
            throw Error(`Failed to get file ${fileName}, from ${bucket}`);
        }
        if (fileName.slice(fileName.length - 4, fileName.length) == 'json') {
            data = data.Body.toString();
        }
        return data;
    }

serverless.yml 파일로 돌아가서 파일을 가져 오기 위한 새로운 기능과 엔드 포인트를 추가 할 수 있습니다. 이미 권한 및 환경 변수를 구성했습니다.


getFile:
        handler: lambdas/endpoints/getFile.handler
        events:
            - http:
                  path: get-file/{fileName}
                  method: GET
                  cors: true

새 엔드 포인트를 생성 할 때 sls deploy를 사용하여 전체 배포를 다시 수행해야 합니다. 그런 다음 새로운 get-file 엔드 포인트를 가져 와서 브라우저 나 Postman에 붙여 넣을 수 있습니다. 요청 끝에 car.json을 추가하면 이 섹션의 앞부분에서 업로드 한 JSON 데이터가 수신됩니다.


API 키로 엔드 포인트 보안 


서버리스를 사용하여 API 엔드 포인트를 빠르고 쉽게 작성할 수 있다는 것은 프로젝트를 시작하고 개념 증명을 작성하는 데 좋습니다. 응용 프로그램의 프로덕션 버전을 만들 때 엔드 포인트에 액세스 할 수 있는 사람에 대해 더 주의를 기울여야 합니다. 다른 사람이 귀하의 API를 공격하는 것을 원하지 않습니다.



API를 보호하기 위해 많은 메소드가 있으며 이 섹션에서는 API 키를 구현할 것입니다. 요청과 함께 API 키를 전달하지 않으면 승인되지 않은 메시지와 함께 실패합니다. 그런 다음 API 키를 제공 할 사람과 API에 액세스 할 수 있는 사람을 제어 할 수 있습니다.


API 키에 사용 정책을 추가하여 각 사람이 귀하의 API를 얼마나 많이 사용하는지 제어 할 수 있습니다. 이를 통해 서비스에 대한 계층 적 사용 계획을 만들 수 있습니다.


시작하기 위해 간단한 API 키를 만들 것입니다. 이렇게 하려면 serverless.yml 파일로 이동하여 공급자에 구성을 추가해야 합니다.


apiKeys:
		myFirstAPIKey

새로운 API 키가 생성됩니다. 이제 서버리스에게 API 키로 보호 할 API 엔드 포인트를 알려줘야 합니다. 이는 일부 API를 보호하고 일부는 공개 상태로 유지하기 위해 수행되었습니다. private 옵션을 추가하여 엔드 포인트를 보호해야 한다고 지정합니다. true :


getUser:
        handler: lambdas/endpoints/getUser.handler
        events:
            - http:
                  path: get-user/{ID}
                  method: GET
                  cors: true
                  private: true

그런 다음이 필드를 원하는 만큼 많은 API에 추가 할 수 있습니다. 이를 배포하기 위해 sls deploy를 다시 실행할 수 있습니다. 이 작업이 완료되면 반환 값에서 API 키를 다시 얻습니다. 이것은 매우 중요하며 곧 사용할 것입니다. get-user API를 요청하면 401 Unauthorized 오류가 발생합니다.


요청이 성공하도록 하려면 요청 헤더에 API 키를 전달해야 합니다. 이를 위해서는 Postman 또는 다른 API 요청 도구를 사용하고 get 요청에 헤더를 추가해야 합니다. API 유형을 사용하여 인증을 선택하면 됩니다. 키는 X-API-KEY 여야 하며 값은 서버리스 배포에서 출력으로 얻은 키입니다.


Screenshot-2019-12-20-at-20.05.53.png 


이제 요청을 하면 성공적으로 응답합니다. 즉, API에 액세스 할 수 있는 유일한 사람은 API 키를 제공 한 사람입니다.


이것은 훌륭하지만 더 많이 할 수 있습니다. 이 API 키에 사용 정책을 추가 할 수 있습니다. 여기에서 한 달의 요청 수와 요청 수행 속도를 제한 할 수 있습니다. 사용자에게 일정량의 API 호출을 제공하는 API 키를 제공 할 수 있으므로 SAAS 제품을 실행하는 데 유용합니다.


사용 계획을 만들려면 공급자에 새 개체를 추가해야 합니다. 할당량 섹션은 해당 API 키를 사용하여 수행 할 수 있는 요청 수를 정의합니다. 애플리케이션에 더 적합한 기간을 DAY 또는 WEEK로 변경할 수 있습니다.


스로틀 섹션을 사용하면 API 엔드 포인트에 얼마나 자주 도달 할 수 있는지 제어 할 수 있습니다. 제한 속도 제한을 추가하면 초당 최대 요청 수가 설정됩니다. 사람들이 서비스 거부 공격을 설정하지 못하게 하므로 매우 유용합니다. burstLimit을 사용하면 API가 rateLimit보다 더 자주 적중하지만 짧은 시간 (보통 몇 초) 동안 만 히트 할 수 있습니다.


usagePlan:
        quota:
            limit: 10
            period: MONTH
        throttle:
            burstLimit: 2
            rateLimit: 1

이를 다시 배포하면 동일한 API 키를 배포하려고 하므로 배포가 실패합니다. API 키는 고유해야 하므로 API 키의 이름을 변경해야 합니다. 이를 배포하고 새 API 키를 Postman에 복사하면 정상적으로 요청을 할 수 있습니다. 초당 너무 많은 요청을 시도하거나 최대 요청 수에 도달하면 429 오류가 발생합니다.

{
    "message": "Limit Exceeded"
}

이는 다음 달까지 이 API 키를 다시 사용할 수 없음을 의미합니다.


사용 계획을 세우는 것이 좋지만 종종 다른 사람들에게 다른 수준의 서비스 액세스 권한을 부여하려고 합니다. 무료 사용자에게 한 달에 100 개의 요청을 주고 유료 사용자는 1000을 받을 수 있습니다. 다른 수의 요청을 제공하는 다른 지불 계획을 원할 수 있습니다. 무제한 요청이 있는 마스터 API 키를 원할 수도 있습니다!


이를 위해 각각 자체 사용 정책이 있는 여러 API 키 그룹을 설정할 수 있습니다. apiKeys 및 usagePlan 섹션을 변경해야 합니다.


apiKeys:
        - free:
              - MyAPIKey3
        - paid:
              - MyPaidKey3
    usagePlan:
        - free:
              quota:
                  limit: 10
                  period: MONTH
              throttle:
                  burstLimit: 2
                  rateLimit: 1
        - paid:
              quota:
                  period: MONTH
                  limit: 1000
              throttle:
                  burstLimit: 20
                  rateLimit: 10

이를 저장하고 배포하면 각각 API 엔드 포인트에 대해 서로 다른 수준의 액세스 권한을 가진 두 개의 새로운 API 키가 제공됩니다.



페이지 정보

조회 25회 ]  작성일20-01-04 11:18

웹학교