AWS API Gateway와 Lambda를 활용해 REST API 구축하기 ③
이번 시간에는 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:"현재 비밀번호"
설명: 특정 게시글을 삭제합니다.
'AWS' 카테고리의 다른 글
AWS EC2 인스턴스 생성, 접속, MySQL 설치, Apache, PHP 연동 [한 번에 끝내기] (6) | 2019.06.24 |
---|---|
Serverless 프레임워크(Framework)의 기본적인 사용법 (0) | 2019.06.04 |
AWS API Gateway와 Lambda를 활용해 REST API 구축하기 ② (0) | 2019.05.21 |
AWS API Gateway와 Lambda를 활용해 REST API 구축하기 ① (0) | 2019.04.24 |
AWS Lambda(Node.js)와 AWS DynamoDB 연동 예제 (2) | 2019.04.24 |