Node.js API Guide 03 — TODO API 만들기 (GET/POST /todos) | 0xccffff Log
Article Node.js API Guide 03 — TODO API 만들기 (GET/POST /todos) Tutorials Feb 20, 2026 Views: 3 Updated: 2026-02-22 Tested: Node 24 LTS, Windows 11 /posts/node-api-03-todos
nodejs api express http beginner
Related posts 미션 해설을 핑계로 PATCH/DELETE를 추가해 CRUD를 완성합니다. req.params(주소창의 숫자), done 토글, 삭제까지 구현하고 PowerShell로 직접 테스트합니다.
지금까지 만든 API 서버 구조를 한 번에 정리하고, 초보자가 꼭 기억해야 할 실전 감각 3가지와 제작 비하인드를 전하며 시리즈를 마무리합니다.
검증/에러처리/간단 인증을 추가해, 초보 단계에서 실전에서 자주 막히는 지점을 한 번에 정리합니다.
TODO를 메모리 대신 todos.json 파일에 저장해, 서버를 재시작해도 데이터가 남도록 만듭니다.
03 — TODO API 만들기 (GET/POST /todos)#
이 글에서는 /todos API를 만들고, GET/POST 요청 을 직접 보내서 동작을 확인합니다.
Prerequisites
02편 완료 (Express 서버가 한 번이라도 실행됐던 상태)
작업 폴더: C:\Workspace\node-api
Windows Terminal 기본 셸: PowerShell
0) 실습 준비 (이전 편과 동일)#
이전과 똑같이 서버를 켤 준비를 해줍니다.
기억이 잘 안 난다면 02. 서버 띄우기 (GET /health) 를 먼저 보고 와도 좋습니다.
VS Code에서 폴더 열기: File > Open Folder... → C:\Workspace\node-api 선택
터미널 열기: VS Code 상단 Terminal > New Terminal
Tip
터미널에 pwd를 입력해서, 현재 위치가 C:\Workspace\node-api가 맞는지 꼭 확인하세요.
Copypwd
Expected result
정상이라면 아래쪽 터미널에 PS C:\...> 같은 프롬프트가 보이고, pwd는 C:\Workspace\node-api를 출력합니다.
1) 오늘 만들 API (2개)#
GET /todos : TODO 목록을 돌려줍니다.
POST /todos : TODO를 하나 추가합니다.
Note
GET 은 “가져오기”, POST 는 “추가하기”로 생각하면 됩니다.
2) server.js에 /todos 규칙 추가하기#
이번 편에서 새로 추가되는 건 크게 4개입니다.
POST로 보낸 JSON을 읽기 (app.use(express.json()))
TODO를 메모리에 들고 있기 (todos, nextId)
GET /todos 라우트
POST /todos 라우트
아래 순서대로 붙여 넣고 저장하면 됩니다. (중간에 헷갈리면 맨 아래 “최종 확인용 전체 코드”로 통째 교체해도 됩니다)
2-1) POST로 보낸 JSON 읽기 켜기#
server.js 상단쪽에 아래 한 줄을 추가합니다.
Copy// 새로 추가된 부분: POST로 보낸 JSON을 읽기 위한 설정
app. use (express. json ());
Note
이게 없으면 POST /todos에서 req.body가 비어있어서, 서버가 제목(title)을 못 읽습니다.
2-2) 메모리 TODO 저장소 만들기#
app.use(...) 아래에 TODO 배열을 하나 만듭니다.
Copy// 새로 추가된 부분: 메모리에 저장되는 TODO 목록 (서버를 끄면 초기화됨)
let nextId = 1 ;
const todos = [];
Note
이 단계에서는 “파일 저장”이 아니라 메모리 저장 입니다.
서버를 껐다가 켜면 todos는 다시 빈 배열로 시작합니다. (다음 글에서 파일 저장으로 바꿉니다)
2-3) GET /todos 추가하기#
/health 아래쪽에 라우트를 하나 더 추가합니다.
Copy// 새로 추가된 부분: GET /todos - 목록 조회
app. get ( "/todos" , ( req , res ) => {
res. json ({ items: todos });
});
2-4) POST /todos 추가하기#
마지막으로 TODO를 추가하는 라우트를 만듭니다.
Copy// 새로 추가된 부분: POST /todos - 하나 추가
app. post ( "/todos" , ( req , res ) => {
const title = req.body?.title;
// 최소 검증
if ( typeof title !== "string" || title. trim (). length === 0 ) {
return res. status ( 400 ). json
Note
최종 확인용 전체 코드 (server.js)# 헷갈리면 아래 코드로 통째로 교체해도 됩니다. (붙여넣고 Ctrl + S 저장)
Copyserver.js const express = require ( "express" );
const app =
3) 서버 재시작 (중요)#
Warning
중요: 코드를 수정했다면 서버를 껐다가 다시 켜야 반영됩니다.
서버가 켜져 있는 터미널에서 Ctrl + C로 끄기
node server.js로 다시 켜기
터미널에서 아래를 실행합니다.
Copynode server.js
Expected result
정상이라면 터미널에 아래처럼 출력됩니다.
Server running: http://localhost:3000
Troubleshooting
Cannot find module 'express'# 보통 npm i express를 실행하지 않았거나, 다른 폴더에서 실행한 경우입니다.
현재 폴더 확인
Copypwd
C:\Workspace\node-api로 이동
Copycd C:\Workspace\node - api
설치 후 다시 실행
Copynpm i express
node server.js
4) GET /todos 확인 (브라우저)#
브라우저 주소창에 아래를 입력합니다.
http://localhost:3000/todos
Expected result
정상이라면 아래처럼 “빈 배열”이 보입니다.
Copy{ "items" :[]}
Tip
여기서 보이는 {"items":[]} 같은 형태가 JSON 입니다.
서버와 클라이언트가 데이터를 주고받을 때 많이 쓰는 텍스트 형식이고, 보통 { "키": "값" }처럼 생겼습니다.
5) POST /todos 요청 보내기 (PowerShell)#
브라우저 주소창만으로는 POST 요청을 보내기 어렵습니다.
그래서 PowerShell로 “서버에게 요청을 보내는 명령”을 실행합니다.
Note
서버를 켜 둔 터미널은 실행 중이라 입력이 어렵습니다.
VS Code에서 Terminal → New Terminal로 터미널을 하나 더 열고 , 그 새 터미널에서 아래 명령을 실행하세요.
아래 명령은 “내 컴퓨터의 서버(localhost
)에 JSON을 보내서 TODO를 추가”합니다.
Copy$body = @ { title = "첫 TODO" } | ConvertTo-Json - Compress
Invoke-RestMethod - Method Post - Uri "http://localhost:3000/todos" - ContentType "application/json; charset=utf-8" - Body $body
Note
PowerShell에서 JSON 문자열을 직접 따옴표로 감싸면(특히 한글) 꼬이기 쉽습니다.
그래서 이 시리즈는 $body = ... | ConvertTo-Json 방식으로 통일합니다. (다음 글에서도 그대로 씁니다)
Expected result
정상이라면 ok: true와 함께, 추가된 TODO가 돌아옵니다. (id가 생깁니다)
Tip
명령이 길면 이렇게 줄여 쓸 수도 있습니다. (irm = Invoke-RestMethod)
Copy$body = @ { title = "두번째 TODO" } | ConvertTo-Json - Compress
irm - Method Post - Uri "http://localhost:3000/todos" - ContentType "application/json; charset=utf-8" - Body $body
Troubleshooting
400 오류가 나요 (title is required)# title이 비었거나, 바디가 비어있는 경우입니다.
아래처럼 그대로 실행해보세요.
Copy$body = @ { title = "할 일" } | ConvertTo-Json - Compress
Invoke-RestMethod - Method Post - Uri "http://localhost:3000/todos" - ContentType "application/json; charset=utf-8" - Body $body
6) 다시 GET /todos로 확인#
브라우저에서 새로고침(F5)합니다.
http://localhost:3000/todos
Expected result
정상이라면 items 안에 방금 추가한 TODO가 들어 있습니다.
7) 작동 원리#
Note
방금 일어난 흐름은 이렇습니다.
CopyBrowser (client) ── GET /todos ──> server.js (http://localhost:3000)
Browser (client) <─ {"items":[...]} ─ server.js
PowerShell (client) ─ POST /todos + JSON ─> server.js
PowerShell (client) <─ {"ok":true,"item":...} ─ server.js
브라우저/PowerShell은 “요청을 보내는 쪽(클라이언트)”
Node.js 서버는 “요청을 받고 응답하는 쪽(서버)”
다음 글#
다음 글에서는 TODO를 메모리가 아니라 파일(todos.json)에 저장 하도록 바꿉니다.
다음 글: 04. 파일 저장하기 (todos.json)
({
ok: false ,
error: "title is required" ,
example: { title: "물 마시기" },
});
}
const todo = {
id: nextId ++ ,
title: title. trim (),
done: false ,
createdAt: new Date (). toISOString (),
};
todos. push (todo);
// 201 = 생성됨(created)
res. status ( 201 ). json ({ ok: true , item: todo });
});
express
();
const PORT = 3000 ;
// 새로 추가된 부분: POST로 보낸 JSON을 읽기 위한 설정
app. use (express. json ());
// 새로 추가된 부분: 메모리에 저장되는 TODO 목록 (서버를 끄면 초기화됨)
let nextId = 1 ;
const todos = [];
app. get ( "/health" , ( req , res ) => {
res. json ({ ok: true });
});
// 새로 추가된 부분: GET /todos - 목록 조회
app. get ( "/todos" , ( req , res ) => {
res. json ({ items: todos });
});
// 새로 추가된 부분: POST /todos - 하나 추가
app. post ( "/todos" , ( req , res ) => {
const title = req.body?.title;
// 최소 검증
if ( typeof title !== "string" || title. trim (). length === 0 ) {
return res. status ( 400 ). json ({
ok: false ,
error: "title is required" ,
example: { title: "물 마시기" },
});
}
const todo = {
id: nextId ++ ,
title: title. trim (),
done: false ,
createdAt: new Date (). toISOString (),
};
todos. push (todo);
// 201 = 생성됨(created)
res. status ( 201 ). json ({ ok: true , item: todo });
});
app. listen ( PORT , () => {
console. log ( `Server running: http://localhost:${ PORT }` );
});
app.use(express.json()) : POST로 보낸 JSON 본문을 req.body로 읽게 해줍니다.
app.get("/todos") : TODO 목록을 { items: [...] } 형태로 돌려줍니다.
app.post("/todos") : title을 검증하고, 배열에 넣은 다음(저장), 새로 만든 TODO를 돌려줍니다.