2-5. 데이터 생성과 조회
이제 데이터베이스를 연동하여 books API 의 기능을 구현해보겠습니다.
먼저, books.controller.js 파일의 상단에 아까 우리가 만든 모델을 불러와주세요.
src/api/books/books.controller.js
- 상단
const Book = require('models/book');
데이터 생성
create 함수부터 구현을 해보도록 하겠습니다.
src/api/books/books.contriller.js
- create
exports.create = async (ctx) => {
// request body 에서 값들을 추출합니다
const {
title,
authors,
publishedDate,
price,
tags
} = ctx.request.body;
// Book 인스턴스를 생성합니다
const book = new Book({
title,
authors,
publishedDate,
price,
tags
});
// 만들어진 Book 인스턴스를, 이렇게 수정 할 수도 있습니다.
// book.title = title;
//.save() 함수를 실행하면 이 때 데이터베이스에 실제로 데이터를 작성합니다.
// Promise 를 반환합니다.
try {
await book.save();
} catch(e) {
// HTTP 상태 500 와 Internal Error 라는 메시지를 반환하고,
// 에러를 기록합니다.
return ctx.throw(500, e);
}
// 저장한 결과를 반환합니다.
ctx.body = book;
};
코드를 작성하고, 저장을 한 다음에 Postman 으로 테스팅을 해보겠습니다.
POST 메소드로 http://localhost:4000/api/books 에 Request Body 는 JSON 형식으로 다음과 같이 입력하여 Send 를 눌러보세요.
{
"title": "React.js Tutorials",
"publishedDate": "2017-07-13",
"authors": [
{
"name": "velopert",
"email": "public.velopert@gmail.com"
},
{
"name": "nakim",
"email": "nakim@nakim.com"
}
],
"tags": ["react.js", "node.js"],
"price": 100
}
다음과 같이 나타나면 잘 된 것입니다.
이제, Send 를 5번정도 눌러보면서 (원한다면 내용도 조금 바꿔보세요) _id
값이 바뀌는것을 확인해보세요.
그 다음엔, Robomongo 를 열어서 데이터베이스에 접속 후, 다음과 같이 데이터를 조회해보세요.
데이터 조회
이제 여러개의 데이터 목록을 조회해보겠습니다.
데이터를 조회 할 때는 .find()
를 사용합니다.
src/api/books/books.controller.js
- list
exports.list = async (ctx) => {
// 변수를 미리 만들어줍니다.
// (let 이나 const 는 scope 가 블록단위이기 때문에, try 바깥에 선언을 해줍니다)
let books;
try {
// 데이터를 조회합니다.
// .exec() 를 뒤에 붙여줘야 실제로 데이터베이스에 요청이 됩니다.
// 반환값은 Promise 이므로 await 을 사용 할 수 있습니다.
books = await Book.find().exec();
} catch (e) {
return ctx.throw(500, e);
}
ctx.body = books;
};
아까 코드보단 간단하지요? 이제 한번 Postman 으로 GET http://localhost:4000/api/books
에 요청을 해보세요.
[
{
"_id": "594fd27d7b8031d36ef0de03",
"title": "React.js Tutorials5",
"publishedDate": "2017-07-13T00:00:00.000Z",
"price": 100,
"__v": 0,
"createdAt": "2017-06-25T15:10:53.654Z",
"tags": [
"react.js",
"node.js"
],
"authors": [
{
"name": "velopert",
"email": "public.velopert@gmail.com",
"_id": "594fd27d7b8031d36ef0de04"
},
{
"name": "nakim",
"email": "nakim@nakim.com",
"_id": "594fd27d7b8031d36ef0de05"
}
]
},
(...)
]
위와 같이 모든 데이터가 나타나게 됩니다.
이번엔, 데이터를 _id의 역순으로 정렬하고 3개만 보여주도록 제한을 주겠습니다. 즉, 최근 생성된 3개만 보여준다는 의미이지요.
src/api/books/books.controller.js
- list
exports.list = async (ctx) => {
// 변수를 미리 만들어줍니다.
// (let 이나 const 는 scope 가 블록단위이기 때문에, try 바깥에 선언을 해줍니다)
let books;
try {
// 데이터를 조회합니다.
// .exec() 를 뒤에 붙여줘야 실제로 데이터베이스에 요청이 됩니다.
// 반환값은 Promise 이므로 await 을 사용 할 수 있습니다.
books = await Book.find()
.sort({_id: -1}) // _id 의 역순으로 정렬합니다
.limit(3) // 3개반 보여지도록 정렬합니다
.exec(); // 데이터를 서버에 요청합니다.
} catch (e) {
return ctx.throw(500, e);
}
ctx.body = books;
};
이렇게, 데이터를 요청하는것을 쿼리라고 부릅니다. 앞으로 다양한 종류의 쿼리를 코드를 작성해가면서 배울 것 입니다. 만약에 미리 어떤것들이 있는지 알고싶다면 공식문서의 queries 페이지를 참조하세요.
단일 데이터 조회
위 부분에서는 데이터의 목록을 조회하는 방법을 알아보았는데요, 이번엔 특정 아이디를 가진 데이터를 조회하는것을 알아보겠습니다.
특정 아이디를 가진 데이터를 조회 할 때는, .findByOne
을 사용합니다.
get
이라는 함수를 만들어서 다음과 같이 코드를 작성하세요.
src/api/books/books.controller.js
- get
exports.get = async (ctx) => {
const { id } = ctx.params; // URL 파라미터에서 id 값을 읽어옵니다.
let book;
try {
book = await Book.findById(id).exec();
} catch (e) {
return ctx.throw(500, e);
}
if(!book) {
// 존재하지 않으면
ctx.status = 404;
ctx.body = { message: 'book not found' };
return;
}
ctx.body = book;
};
데이터가 존재하지 않으면 HTTP 상태 404를 반환합니다.
그 다음엔 /:id
라우트에 방금 만든 get 함수를 전달하세요.
src/api/books/index.js
const Router = require('koa-router');
const books = new Router();
const booksCtrl = require('./books.controller');
books.get('/', booksCtrl.list);
books.get('/:id', booksCtrl.get);
books.post('/', booksCtrl.create);
books.delete('/', booksCtrl.delete);
books.put('/', booksCtrl.replace);
books.patch('/', booksCtrl.update);
module.exports = books;
이렇게 API 를 만들고 나면, 아까 목록에 나타났었던 id 를 주소 뒤에 붙여넣으세요.
GET http://localhost:4000/api/books/594fd2917b8031d36ef0de0c
이런식으로 요청하면, 주어진 id 로 데이터 하나를 조회하게 됩니다.
그리고 맨 마지막 문자를 다른 값으로 변형시켜보세요. 594fd2917b8031d36ef0de0f
이런식으로 말이죠. 404 가 나타나게 됩니다. 하지만, 아예 문자 하나를 지워버리거나 하나를 더 넣어버리면 Internal Error 가 나타날것입니다.
id 를 파라미터로 받을때는, 에러를 처리해주거나, 사전에 id 검증작업을 거쳐야합니다. id 검증작업은 나중에 해보도록하고, 이번엔 에러를 처리해주는 방식으로 코드를 고치겠습니다.
src/api/books/books.controller.js
- get
exports.get = async (ctx) => {
const { id } = ctx.params; // URL 파라미터에서 id 값을 읽어옵니다.
let book;
try {
book = await Book.findById(id).exec();
} catch (e) {
if(e.name === 'CastError') {
ctx.status = 400;
return;
}
return ctx.throw(500, e);
}
if(!book) {
// 존재하지 않으면
ctx.status = 404;
ctx.body = { message: 'book not found' };
return;
}
ctx.body = book;
};