추상화?
로직을 묶는다는 것은 추상화를 한다는 것 공통된 패턴을 빼내 항상 일정한 규격에 맞게 행동하도록 코드를 재구축하는것.
현 코드에서는 statusCode, header를 정하고 http body에 표시하는것을 공통으로 쓰고있고 각 요청들마다 url과 메소드등이 필요하다.
잘추상화한 함수를 만들어둬서 타입체크를하도록 잘막아둬야 굳이 런타임에 가지않아도, 유저가 사용하기전에 미리 테스트를 해보기 때문에 안전하다.
api.js
기본구조로써 Route와 APIResponse가 들어갈예정. 모듈화가되어 route를 export 할수있게됨
//@ts-check
/**
* @typedef APIResponse
* @property {number} statusCode
* @property {*} body
*/
// /**
// * @tyoedef Route
// * @property {string} url
// * @property {string} method
// * @property {(valuse:Object)=> string} callback
// */
/**
* @typedef Route
* @property {RegExp} url
* @property {'GET' | 'POST'} method
* @property {()=> Promise<APIResponse>} callback
*/
/** @type {Route[]} */
const routes = [
...
]
// 이 파일은 모듈이고 모듈에서 route를 내보냄
module.exports = {
routes
}
1. route만들기
main.js
//@ts-check
// npm run server
/**
* 글(post) API
*
* 전체보기:GET /posts
* 특정글보기:GET /posts/:id
* 글쓰기:POST /posts
*/
// 모듈을가져올땐 require이용
// http 모듈로 서버만들기
const http = require('http')
const { mainModule } = require('process')
// 내가만든 모듈에서 route가져오기
const { routes, posts } = require('./api')
const server = http.createServer((req, res) => {
async function main() {
// 일치하는 라우트찾기
const route = routes.find(
(_route) =>
req.url &&
req.method &&
_route.url.test(req.url) &&
_route.method === req.method
)
//route가 없을때
if (!req.url || !route) {
res.statusCode = 404
res.end('Not found1')
return
}
const regexResult = route.url.exec(req.url)
if (!regexResult) {
res.statusCode = 404
res.end('Not found2')
return
}
//post처리
/** @type {Object.<string, *> | undefined} */
const regBody =
//header가 json의 조건을 만족해야(&&) 프로미스가 실행되고 아니면(||) undefined
(req.headers['content-type'] === 'application/json' &&
(await new Promise((resolve, reject) => {
req.setEncoding('utf-8')
req.on('data', (data) => {
try {
resolve(JSON.parse(data))
} catch {
reject(new Error('파싱이 실패했음'))
}
})
}))) ||
undefined
// console.log(redBody) http POST localhost:8080/posts a=1 ==> {"a":"1"}
// route가 있을때
const result = await route.callback(regexResult, regBody)
res.statusCode = result.statusCode
// res.end(result.body)
//body가 {}일때랑 string일때 대응
if (typeof result.body === 'string') {
res.end(result.body)
} else {
res.setHeader('Content-type', 'application/json; charset=utf-8')
res.end(JSON.stringify(result.body))
}
}
main()
})
const PORT = 8080
server.listen(PORT, () => {
console.log(`the server is listening at port: ${PORT}`)
})
api.js
//@ts-check
/**
* @typedef Post
* @property {string} id
* @property {string} title
* @property {string} content
*/
/** @type {Post[]} */
const posts = [
{ id: '1', title: 'my first post', content: 'hi' },
{ id: '2', title: 'my second post', content: 'bye' },
]
/**
* @typedef APIResponse
* @property {number} statusCode
* @property {string | object} body
*/
// /**
// * @tyoedef Route
// * @property {string} url
// * @property {string} method
// * @property {(valuse:Object)=> string} callback
// */
/**
* @typedef Route
* @property {RegExp} url
* @property {'GET' | 'POST'} method
* @property {(maches: string[], body: object | undefined)=> Promise<APIResponse>} callback
*/
/** @type {Route[]} */
const routes = [
{
url: /^\/posts$/, //'posts' -> regExe로 고쳐야함
method: 'GET',
callback: async () => ({
statusCode: 200,
body: posts,
}),
},
{
url: /^\/posts\/([a-zA-Z0-9-_]+)$/, //'posts/:id' -> regExe
method: 'GET',
callback: async (maches) => {
console.log(maches)
const postId = maches[1]
if (!postId) {
return {
statusCode: 404,
body: 'Not found3',
}
}
const post = posts.find((_post) => _post.id === postId)
if (!post) {
return {
statusCode: 404,
body: 'Not found',
}
}
return {
statusCode: 200,
body: post,
}
},
},
{
url: /^\/posts$/, //'posts' -> regExe
method: 'POST',
callback: async (_, body) => {
if (!body) {
return {
statusCode: 400,
body: 'no body',
}
}
/** @type {string} */
const title = body.title
const newPost = {
id: title.replace(/\s/g, '_'),
title,
content: body.content,
}
posts.push(newPost)
// statusCode: 200,
// body: {},
return {
statusCode: 200,
body: newPost,
}
},
},
]
// 이 파일은 모듈이고 모듈에서 route를 내보냄
module.exports = {
routes,
posts,
}
get posts/:id
main.js 에서 regexResult 값 req.url을 콜백에 넘겨줌
api.js 에서 async(matches)를 통해 받아옴
post
main.js 에서 regexBody 값으로 파싱된 데이타를 콜백에 넘겨줌
api.js 에서 async(_, body)를 통해 받아옴(여기서 _는 maches를 의미)
2. APIResponse
반응형
'Backend > node.js' 카테고리의 다른 글
[node.js] express 설치와 환경세팅 (0) | 2021.09.04 |
---|---|
[node.js] 간단한 데이터베이스만들기(JSON) (0) | 2021.09.04 |
[nodejs] 간단한 restfulAPI 서버만들기2 (0) | 2021.08.30 |
[nodejs] 간단한 restfulAPI 서버만들기 (0) | 2021.08.27 |
nodemon 노드몬 설치 사용방법 (0) | 2021.08.03 |