안경잡이개발자

728x90
반응형

  이번 시간에는 AWS Lambda와 MongoDB를 활용하여 하나의 게시물(Board) API를 완전히 개발해보는 시간을 가져보도록 하겠습니다. 따라서 가장 먼저, 다음과 같이 /board 경로에 GET, POST, PUT, DELETE 메소드의 API를 Gateway로 열어줍니다. 그리고 /board/{proxy+} 경로의 모든 메소드를 사용할 수 있도록 합니다.

 

  /board/{proxy+}로 설정하면, 모든 Path Parameter를 받을 수 있게 됩니다.

 

 

  이후에 소스코드를 작성합니다. 우리가 작성할 게시물 Rest API의 기본적인 명세는 다음과 같습니다.

 

[ 게시물 ]

 

- 게시물 번호

- 게시물 작성자

- 게시물 비밀번호

- 게시물 내용

- 게시물 작성일자

 

  소스코드는 다음과 같습니다.

"use strict";
const mongoose = require('mongoose');
const MONGODB_URI = process.env.MONGODB_URI;

/* Board 오브젝트를 정의합니다. */
const boardSchema = mongoose.Schema({
    id: {
        type: Number,
        required: true
    },
    name: {
        type: String,
        required: true
    },
    password: {
        type: String,
        required: true
    },
    content: {
        type: String,
        required: true
    },
    date: {
        type: Date,
        required: true
    }
});

/* 하나의 연결 객체를 반복적으로 사용합니다. */
let connection = null;

const connect = () => {
  if (connection && mongoose.connection.readyState === 1) return Promise.resolve(connection);
  return mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true }).then(
    conn => {
      connection = conn;
      return connection;
    }
  );
};

module.exports.handler = (event, context, callback) => {
  let operation = event.httpMethod;
  let Board = mongoose.model('board', boardSchema);
  let proxy, password;
  switch (operation) {
    case 'GET':
      /* 
        경로: /board
        설명: 전체 게시글 정보를 불러옵니다.
      */
      if(event.pathParameters === null) {
        let query = {};
        if(event.queryStringParameters.name) {
          query.name = {$regex:event.queryStringParameters.name, $options: 'i'};
        }
        if(event.queryStringParameters.content) {
          query.content = {$regex:event.queryStringParameters.content, $option: 'i'};
        }
        // name과 content를 이용하여 검색한 결과를 내림차순으로 반환합니다.
        connect().then(() =>
        Board.find(query)
        .select("-password")
        .sort({id: -1})
        .exec(function(error, boards) {
            if(error) {
              context.done(null, { 'statusCode': 500, 'body': JSON.stringify(error) });
            }
            else {
              context.done(null, { 'statusCode': 200, 'body': JSON.stringify(boards) });
            }
        }));
      }
      /* 
        경로: /board/:id
        설명: 특정 게시글 정보를 불러옵니다.
      */
      else {
        proxy = event.pathParameters.proxy;
        connect().then(() =>
        Board.findOne({id:proxy})
        .select("-password")
        .exec(function(err, board) {
            if(err) {
              context.done(null, { 'statusCode': 500, 'body': JSON.stringify(err) });
            }
            else if(!board) {
              context.done(null, { 'statusCode': 500, 'body': JSON.stringify("Board not found.") });
            }
            else {
              context.done(null, { 'statusCode': 200, 'body': JSON.stringify(board) });
            }
        }));
      }
      break;
    case 'POST':
      /* 
        경로: /board
        파라미터: {"name":"작성자","content":"내용","password":"비밀번호"}
        설명: 특정 게시글을 작성합니다.
      */
      let lastId = 0;
      // 가장 최근에 작성된 게시물 번호를 가져옵니다.
      connect().then(() =>
      Board.findOne({})
        .sort({id: -1})
        .exec(function(err, board) {
          if(err) {
            context.done(null, { 'statusCode': 500, 'body': err });
          } else {
            lastId = board ? board.id : 0;
            const { name, content, password } = JSON.parse(event.body);
            const newBoard = new Board({ name, content, password });
            newBoard.date = new Date();
            newBoard.id = lastId + 1;
            // 새로운 글을 등록합니다.
            newBoard.save(function(err, board) {
              if(err) {
                context.done(null, { 'statusCode': 500, 'body': JSON.stringify(err) });
              } else {
                context.done(null, { 'statusCode': 200, 'body': JSON.stringify(lastId + 1) });
              }
            });
          }
        })
      );
      break;
    case 'PUT':
      /* 
        경로: /board/:id
        헤더: password:"현재 비밀번호"
        파라미터: {"name":"작성자","content":"내용","password":"비밀번호"}
        설명: 특정 게시글을 수정합니다.
      */
      proxy = event.pathParameters.proxy;
      password = event.headers.password;
      // 사용자가 입력한 번호의 게시물을 찾습니다.
      connect().then(() =>
      Board.findOne({id:proxy})
      .exec(function(err, board) {
          if(err) {
              context.done(null, { 'statusCode': 500, 'body': JSON.stringify(err) });
          }
          else if(!board) {
              context.done(null, { 'statusCode': 500, 'body': JSON.stringify("Board not found.") });
          }
          else {
              if(board.password != password) {
                context.done(null, { 'statusCode': 500, 'body': JSON.stringify("Password is incorrect.") });
              } else {
                  const { name, content, password } = JSON.parse(event.body);
                  // 사용자가 입력한 name, content, password에 맞게 정보를 변경합니다.
                  Board.findOneAndUpdate({id:proxy}, { name, content, password })
                  .exec(function(err, board) {
                      if(err) {
                        context.done(null, { 'statusCode': 500, 'body': JSON.stringify(err) });
                      }
                      else {
                        context.done(null, { 'statusCode': 200, 'body': JSON.stringify('success') });
                      }
                  });
              }
          }
      }));
      break;
    case 'DELETE':
      /* 
        경로: /board/:id
        헤더: password:"현재 비밀번호"
        설명: 특정 게시글을 삭제합니다.
      */
      proxy = event.pathParameters.proxy;
      password = event.headers.password;
      connect().then(() =>
      Board.findOne({id:proxy})
      .exec(function(err, board) {
          if(err) {
              context.done(null, { 'statusCode': 500, 'body': JSON.stringify(err) });
          }
          else if(!board) {
              context.done(null, { 'statusCode': 500, 'body': JSON.stringify("Board not found.") });
          }
          else {
              if(board.password != password) {
                context.done(null, { 'statusCode': 500, 'body': JSON.stringify("Password is incorrect.") });
              } else {
                // 사용자가 입력한 번호에 해당하는 게시물을 삭제합니다.
                Board.findOneAndRemove({id:proxy})
                .exec(function(err, board) {
                    if(err) {
                      context.done(null, { 'statusCode': 500, 'body': JSON.stringify(err) });
                    }
                    else {
                        context.done(null, { 'statusCode': 200, 'body': JSON.stringify('success') });
                    }
                });
              }
          }
      }));
      break;
    default:
      callback(new Error(`Unrecognized operation "${operation}"`));
  }
};

 

  테스트 결과는 다음과 같습니다.

 

1. 게시글 리스트 보기


경로: /board 
설명: 전체 게시글 정보를 불러옵니다. 

 

 

 

2. 게시물 정보 확인하기


경로: /board/:id 

설명: 특정 게시글 정보를 불러옵니다. 

 

 

3. 게시물 등록하기


경로: /board 
파라미터: {"name":"작성자","content":"내용","password":"비밀번호"} 
설명: 특정 게시글을 작성합니다. 

 

 

4. 게시물 수정하기

 

경로: /board/:id
헤더: password:"현재 비밀번호" 
파라미터: {"name":"작성자","content":"내용","password":"비밀번호"} 
설명: 특정 게시글을 수정합니다. 

 

 

5. 게시물 삭제하기


경로: /board/:id 
헤더: password:"현재 비밀번호" 
설명: 특정 게시글을 삭제합니다. 

 

728x90
반응형