๐Ÿ˜ŽNode JS๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Scrach์˜ ํ”„๋ ˆ์ž„ ์—†์ด REST Api ๊ตฌ์ถ•

15719 ๋‹จ์–ด nodejavascriptbeginnerswebdev
๋ณธ ๋…ผ๋ฌธ์—์„œ, ์šฐ๋ฆฌ๋Š” Express, Oak ๋“ฑ ์–ด๋– ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๋„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , node js์—์„œ CRUD rest api๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šธ ๊ฒƒ์ด๋‹ค๐Ÿ˜.๊ธฐ๋ณธ ๋…ธ๋“œ http ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์ถ•ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๐Ÿ”ฅ ์„œ๋ฒ„ ์‹œ์ž‘ ๋ฐ ์‹คํ–‰


์šฐ์„ , node js์—์„œ http ํŒจํ‚ค์ง€๋ฅผ ๊ฐ€์ ธ์˜ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค.๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๋Š” ๊ทธ ์ค‘์—์„œ createServer() ๋ฐฉ๋ฒ•์„ ํ˜ธ์ถœํ•  ๊ฒƒ์ด๋‹ค. ์ด๊ฒƒ์€ ์šฐ๋ฆฌ์—๊ฒŒ http.Server๋ฅ˜์˜ ์‹ค๋ก€๋ฅผ ์ œ๊ณตํ•  ๊ฒƒ์ด๋‹ค.์ดํ›„์— ์šฐ๋ฆฌ๋Š” listen() ํด๋ž˜์Šค ์‹ค๋ก€์—์„œ http.Server ๋ฐฉ๋ฒ•์„ ํ˜ธ์ถœํ•  ๊ฒƒ์ด๋‹ค. ์ด ํด๋ž˜์Šค ์‹ค๋ก€๋Š” HTTP ์„œ๋ฒ„ ํƒ์ง€ ์—ฐ๊ฒฐ์„ ์‹œ์ž‘ํ•  ๊ฒƒ์ด๋‹ค.๐Ÿ˜‰.
const http = require('http');
const server = http.createServer();
const PORT = process.env.PORT || 5000;
server.listen(PORT, () => console.log(`Server listening on port ${PORT}!!!`));

http์— ๊ด€ํ•˜์—ฌ.createServer๏ผˆ๏ผ‰

http.createServer() ์˜ต์…˜ ๋งค๊ฐœ ๋ณ€์ˆ˜requestListener๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.HTTP ์„œ๋ฒ„ ๋Œ€์ƒ์€ ์ปดํ“จํ„ฐ์˜ ํฌํŠธ๋ฅผ ๊ฐ์ฒญํ•˜๊ณ  ์š”์ฒญ์„ ํ•  ๋•Œ๋งˆ๋‹ค ํ•จ์ˆ˜ RequestListener๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.์ด๊ฒƒrequestListener์€ ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.์—ฌ๊ธฐrequestListener์—์„œ ์š”์ฒญ๊ณผ ์‘๋‹ต ๋งค๊ฐœ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.์ด ํ•จ์ˆ˜์—์„œ, ์šฐ๋ฆฌ๋Š” ๋ชจ๋“  ์ „์†ก ์š”์ฒญ์˜ req.url ์™€ req.method ๋ฅผ ๊ฒ€์‚ฌํ•œ ๋‹ค์Œ, ์กฐ๊ฑด๋ถ€๋กœ ์—…๋ฌด ๋…ผ๋ฆฌ๋ฅผ ์ง‘ํ–‰ํ•˜์—ฌ, ๊ธฐ๋Œ€ํ•˜๋Š” ์‘๋‹ต์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋˜๋Œ๋ ค์ค„ ๊ฒƒ์ด๋‹คโœจ .

๐Ÿฅณ CRUD ๊ธฐ๋ฐ˜restapi ๊ตฌ์ถ•


์ด๋ก ๋งŒ์œผ๋กœ๋„ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ๊ฐ„๋‹จํ•œ CRUD api๋ฅผ ๊ตฌ์ถ•ํ•˜์—ฌ TODO๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.Thisgithub ๋ฉ”๋ชจ๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•œ ๋งํฌ๋กœ ์™„์ „ํ•œ ์›๋ณธ ์ฝ”๋“œ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.์—ฌ๊ธฐ ์„œ๋ฅ˜ ๋‘ ๊ฐœ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
๊ฐ๊ฐ data.js ๊ณผ todoController.js ์ด๋‹ค.todo.js์—์„œ ์ด ๊ฐ•์ขŒ์— ์‚ฌ์šฉํ•  ๊ฐ€์ƒ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.๋‚˜๋Š” ์ด ๊ฐ•์ขŒ๋ฅผ ์œ„ํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ™์€ ๊ฒƒ์„ ์ถ”๊ฐ€ํ•ด์„œ ์ผ์„ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.todoController.js์—์„œ, ์šฐ๋ฆฌ๋Š” ์ด ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, id๋ฅผ ํ†ตํ•ด todo๋ฅผ ์ฐพ๊ฑฐ๋‚˜ ๋ชจ๋“  ์œ ์‚ฌํ•œ todo๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.๋„ˆ๋Š” ์ด ๋‘ ํŒŒ์ผ์„ ์ž์œ ๋กญ๊ฒŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.\
์šฐ๋ฆฌ๋Š” TODO๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์„ฏ ๊ฐœ์˜ ๋…ธ์„ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๊ฒƒ์ด๋‹ค.
  • url: /api/todos์™€ ๋ฐฉ๋ฒ•: GET - ๋ชจ๋“  TODO์˜ ๊ฒฝ๋กœ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  • url: /api/todos/:id์™€ ๋ฐฉ๋ฒ•: GET - id๋ฅผ ํ†ตํ•ด todo์˜ ๊ฒฝ๋กœ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  • url: /api/todos/:id์™€ ๋ฐฉ๋ฒ•: PATCH - todo id์— ๋”ฐ๋ผ todo๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฃจํŠธ
  • url: /api/todos/:id์™€method: DELETE - id๋ฅผ ํ†ตํ•ด todo๋ฅผ ์‚ญ์ œํ•˜๋Š” ๋ฃจํŠธ
  • url: /api/todos/:์™€ ๋ฐฉ๋ฒ•: POST - ์ƒˆ todo๋ฅผ ๋งŒ๋“œ๋Š” ๋ฃจํŠธ์ž…๋‹ˆ๋‹ค.
  • ์–ด๋–ค ๋ฃจํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์ „์— res์˜ requestListener ๋งค๊ฐœ ๋ณ€์ˆ˜์— ์กด์žฌํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์•Œ์•„์•ผ ํ•œ๋‹ค.
  • writeHead() - HTTP ์ƒํƒœ ์ฝ”๋“œ์™€ ์‘๋‹ต ํ—ค๋“œ ์ปฌ๋ ‰์…˜์„ ํด๋ผ์ด์–ธํŠธ์— ๋‹ค์‹œ ๋ณด๋ƒ…๋‹ˆ๋‹ค.์ƒํƒœ ์ฝ”๋“œ๋Š” ์š”์ฒญํ•œ ๊ฒฐ๊ณผ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.์˜ˆ๋ฅผ ๋“ค์–ด ๋ชจ๋“  ์‚ฌ๋žŒ์ด ์ด์ „์— 404 ์˜ค๋ฅ˜๋ฅผ ๋งŒ๋‚ฌ๋Š”๋ฐ, ์ด๊ฒƒ์€ ํŽ˜์ด์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.์˜ˆ์‹œ ์„œ๋ฒ„๋Š” ์ฝ”๋“œ 200์„ ๋˜๋Œ๋ ค ์„ฑ๊ณต์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
  • end() - ์ด ๋ฐฉ๋ฒ•์€ ์„œ๋ฒ„์— ์‹ ํ˜ธ๋ฅผ ๋ณด๋‚ด์„œ ๋ชจ๋“  ์‘๋‹ต ํ—ค๋”์™€ ๋ณธ๋ฌธ์ด ๋ฐœ์†ก๋˜์—ˆ์Œ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.์ด ์„œ๋ฒ„๋Š” ์ด ๋ฉ”์‹œ์ง€๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ๋‹ค๊ณ  ์—ฌ๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค.๋ฐฉ๋ฒ•๋ชจ๋“  ์‘๋‹ต์— end () ๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.์ด ๋ฐฉ๋ฒ•์—์„œ, ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋˜๋Œ๋ ค ์ฃผ๊ณ  ์‹ถ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์‘๋‹ต์œผ๋กœ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌํ•  ๊ฒƒ์ด๋‹ค.
  • (1) ๋ชจ๋“  ์—…๋ฌด ๋…ธ์„ ์„ ํ™•๋ณดํ•œ๋‹ค.


    ์šฐ์„  ์ˆ˜์‹  ์š”์ฒญurl๊ณผ method๊ฐ€ ๊ฐ๊ฐ /api/todos๊ณผGET์ธ์ง€ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.๋งŒ์•ฝ ๊ทธ๋ ‡๋‹ค๋ฉด, ์šฐ๋ฆฌ๋Š” data.js ์˜ ๋„์›€์œผ๋กœ todoController.js ๋ชจ๋“  ๋Œ€๊ธฐ ์‚ฌํ•ญ์„ ๊ฐ€์ ธ์˜ค๊ณ , ๋ชจ๋“  ๊ฒƒ์ด ์ˆœ์กฐ๋กญ๋‹ค๋ฉด, ์šฐ๋ฆฌ๋Š” ์ƒํƒœ ์ฝ”๋“œ๋ฅผ 200์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์š”์ฒญ์ด ์„ฑ๊ณตํ–ˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.์—ฌ๊ธฐ์— ์ œ๋ชฉContent-Type : application/json์„ ์„ค์ •ํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋˜๋Œ์•„์˜ค๋Š” ๋‚ด์šฉ์˜ ์œ ํ˜•์ด JSON ํ˜•์‹์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.๋ชจ๋“  ๋ฃจํŠธ์™€ ์š”์ฒญ์— ์ด ํ—ค๋”๋ฅผ ์„ค์ •ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ JSON ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.๊ทธ๋ฆฌ๊ณ  ์š”์ฒญํ•œ url ์ด๋‚˜ method ์ด ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด, ์ƒํƒœ ์ฝ”๋“œ๋ฅผ 404๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ฐพ์„ ์ˆ˜ ์—†์Œ์„ ์˜๋ฏธํ•˜๋ฉฐ, ๋ฃจํŠธ์—์„œ ์ฐพ์„ ์ˆ˜ ์—†๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์‘๋‹ต์œผ๋กœ ๋ณด๋‚ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
    const server = http.createServer(async (req, res) => {
        if (req.url === '/api/todos' && req.method === 'GET') {
            const todos = await Todo.findAll();
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify(todos));
        }   else {
            res.writeHead(404, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ message: 'Route not found!' }));
        }
    });
    
    ๊ฐœ๋ฐœ ๊ณผ์ •์—์„œ API๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ์›ํ•˜๋Š” ๋Œ€๋กœ ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.๋‚˜๋Š” ์šฐ์ฒด๋ถ€๊ฐ€ ๋‚˜์˜ API๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์„ ๋”์šฑ ์ข‹์•„ํ•œ๋‹ค.์–ด๋–ค ํ”Œ๋žซํผ์—์„œ๋“  ๊ตฌ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹คhere\

    (2) id๋ฅผ ํ†ตํ•ด todo๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฃจํŠธ


    ์ด ๋…ธ์„ ์— ๋Œ€ํ•ด ์šฐ๋ฆฌ์˜ ์ ˆ์ฐจ๋„ ๊ฐ™์„ ๊ฒƒ์ด๋‹ค.์œ ์ผํ•œ ์ฐจ์ด์ ์€, ์šฐ๋ฆฌ๋Š” ๋ชจ๋“  todo๋ฅผ ์–ป์ง€ ์•Š๊ณ , ํ•˜๋‚˜์˜ todo๋ฅผ ๊ฐ€์ ธ์™€ ์‘๋‹ต์„ ๋˜๋Œ๋ ค๋ฐ›๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.์ด ๋ฃจํŠธ์— ๋™์  ๋งค๊ฐœ ๋ณ€์ˆ˜ id๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ฃจํŠธ ์ž์ฒด์— ์ „๋‹ฌ๋˜๊ณ  ํŠน์ •ํ•œ todo ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค.
    if (req.url.match(/\/api\/todos\/([a-z A-Z 0-9]+)/) && req.method === 'GET') {
            try {
                const id = req.url.split('/')[3];
                const todo = await Todo.findById(id);
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify(todo));
            } catch (error) {
                res.writeHead(404, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ message: 'Todo not found!' }));
            }
        }
    
    ํ…Œ์ŠคํŠธ ํ›„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‘๋‹ต์ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.\

    (3) ๋Œ€๊ธฐ์‚ฌํ•ญ id์— ๋”ฐ๋ผ ๋Œ€๊ธฐ์‚ฌํ•ญ์„ ์‚ญ์ œํ•˜๋Š” ๋ฃจํŠธ


    ์ด ๋…ธ์„ ์—์„œ ์šฐ๋ฆฌ๋Š” ๋จผ์ € req.method๊ฐ€ DELETE์ธ์ง€ ํ™•์ธํ•  ๊ฒƒ์ด๋‹ค.\
    ์ด ๋ฃจํŠธ๋Š” ์ƒ๊ธฐ ๋ฃจํŠธ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์œ ์ผํ•œ ์ฐจ์ด์ ์€ id์— ๋”ฐ๋ผ todo๋ฅผ ์‚ญ์ œํ•˜๊ณ , id๋ฅผ ํ†ตํ•ด ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์‘๋‹ต์œผ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
    if (req.url.match(/\/api\/todos\/([a-z A-Z 0-9]+)/) && req.method === 'DELETE') {
            try {
                const id = req.url.split('/')[3];
                await Todo.deleteById(id);
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ message: 'Todo deleted successfully!!!' }));
            } catch (error) {
                console.log(error);
                res.writeHead(404, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ message: 'Todo not found!' }));
            }
        }
    
    ใ€Š์šฐ์ฒด๋ถ€ใ€‹์—์„œ ํ…Œ์ŠคํŠธํ•œ ํ›„

    ์ด๋ฒˆ์—” ์ด๋ ‡๊ฒŒ.๋‚˜๋จธ์ง€ ๋‘ ๋…ธ์„ , ์ฆ‰ ํ•˜๋‚˜๋Š” todo๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๊ณ , ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” todo๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š”์ง€ ์•Œ์•„๋ณด๋ ค๋ฉดsatishnaikawadi.me
    ๋‚˜๋Š” ๋„ˆํฌ๋“ค์ด ์ ์–ด๋„ ์–ด๋Š ์ •๋„์— ๋‚ด๊ฐ€ ์ด ๋ฌธ์žฅ์—์„œ ํ•ด์„ํ•œ ๋‚ด์šฉ์„ ์ดํ•ดํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž€๋‹ค๐Ÿ˜‡. ๊ถ๊ธˆํ•œ ๊ฒƒ์ด ์žˆ์œผ๋ฉด ์–ธ์ œ๋“ ์ง€ ๋ฌผ์–ด๋ณด์„ธ์š”.

    ์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ