이번 편의 결과물: 코드 작성은 없습니다. 08편에서 fetch로 json-server와 통신하기 전에, 요청·응답을 읽고 상태 코드를 해석하는 법을 갖춥니다. · 다루는 개념: HTTP 요청·응답 구조, 상태 코드, JSON 직렬화, REST 자원 개념
이 편에서 만드는 파일
(코드 없음) 04편부터 notes-app 프로젝트 폴더를 만듭니다.
개념 정리
HTTP 요청과 응답의 모양
브라우저가 서버에 보내는 요청과 서버가 돌려주는 응답은 둘 다 “시작 줄 + 헤더 + (있으면) 본문” 구조입니다.
POST /notes HTTP/1.1
Host: localhost:3001
Content-Type: application/json
{"title":"새 메모","body":"내용"}HTTP/1.1 201 Created
Content-Type: application/json
{"id":"n5","title":"새 메모","body":"내용"}| 구성 요소 | 요청에서 | 응답에서 |
|---|---|---|
| 시작 줄 | 메서드 + 경로 + 버전(POST /notes HTTP/1.1) | 버전 + 상태 코드 + 상태 문구(HTTP/1.1 201 Created) |
| 헤더 | 부가 정보(Content-Type, Authorization 등) | 부가 정보(Content-Type, Cache-Control 등) |
| 본문 | 서버로 보낼 데이터(있을 수도, 없을 수도) | 서버가 돌려준 데이터 |
메서드 — 무엇을 하려는 요청인지
| 메서드 | 의미 | notes-app에서의 쓰임(08편) |
|---|---|---|
GET | 자원 조회 | 메모 목록·상세 가져오기 |
POST | 자원 생성 | 새 메모 추가 |
PUT | 자원 전체 교체 | 메모 내용 전체 수정 |
DELETE | 자원 삭제 | 메모 삭제 |
상태 코드 — 결과를 숫자로 요약
| 대역 | 의미 | 예 |
|---|---|---|
2xx | 성공 | 200 OK, 201 Created, 204 No Content |
3xx | 리다이렉션 | 304 Not Modified |
4xx | 클라이언트 오류(요청이 잘못됨) | 400 Bad Request, 404 Not Found |
5xx | 서버 오류 | 500 Internal Server Error |
fetch는 4xx·5xx 응답을 받아도 예외를 던지지 않습니다. 네트워크 자체가 끊겼을 때만 예외를 던집니다. 그래서 08편에서 response.ok(상태 코드가 200번대인지)를 직접 확인하는 코드를 씁니다.
JSON — 자바스크립트 객체를 문자열로
JSON(JavaScript Object Notation)은 객체·배열·문자열·숫자·불리언·null만으로 데이터를 표현하는 텍스트 형식입니다. 네트워크로는 문자열만 보낼 수 있으므로, 자바스크립트 객체를 보내려면 문자열로 바꾸는 과정(직렬화)이 필요합니다.
| 방향 | 함수 | notes-app에서의 쓰임 |
|---|---|---|
| 객체 → 문자열(직렬화) | JSON.stringify(note) | fetch의 body에 넣을 때 |
| 문자열 → 객체(역직렬화) | JSON.parse(text) 또는 response.json() | 서버 응답을 다시 객체로 쓸 때 |
JSON은 자바스크립트 객체 리터럴과 비슷하지만 다릅니다.
| 항목 | 자바스크립트 객체 리터럴 | JSON |
|---|---|---|
| 키 표기 | 따옴표 생략 가능({title: "..."}) | 키를 항상 큰따옴표로 감쌈({"title": "..."}) |
함수·undefined | 값으로 넣을 수 있음 | 표현 불가(직렬화 시 사라짐) |
날짜(Date) | 객체로 다룸 | 문자열로 변환됨(예: updatedAt 필드) |
| 주석 | 가능 | 불가 |
notes.seed.json의 updatedAt 필드가 2026-09-16T09:30:00+09:00처럼 문자열인 이유가 여기 있습니다. Date 객체는 JSON으로 직렬화되는 순간 ISO 문자열로 바뀝니다.
REST 자원 개념
REST는 데이터를 “자원(resource)“으로 보고, URL 경로로 자원을 가리키고, HTTP 메서드로 그 자원에 무엇을 할지 표현하는 방식입니다. json-server(08편에서 사용)는 이 규칙을 그대로 흉내 냅니다.
| 요청 | 의미 |
|---|---|
GET /notes | 메모 전체 목록 조회 |
GET /notes/n1 | id가 n1인 메모 하나 조회 |
POST /notes | 새 메모 생성 |
PUT /notes/n1 | n1 메모 전체 교체 |
DELETE /notes/n1 | n1 메모 삭제 |
경로 안의 /notes가 “메모”라는 자원 전체를, /notes/n1이 그중 하나를 가리킵니다. 동사(만들기·지우기)는 URL이 아니라 메서드로 표현하는 것이 REST 스타일입니다.
개발자 도구로 확인하기
1. Network 탭 열고 아무 페이지 새로고침
개발자 도구의 Network 탭을 열고 페이지를 새로고침합니다. 요청 목록이 쌓이는 것을 확인합니다.
2. 요청 하나 선택해 Headers 확인
목록에서 문서 요청(보통 첫 번째 줄, Type이 document)을 클릭하고 Headers 탭에서 Request Method, Status Code, Content-Type을 찾습니다.
3. JSON 응답 찾아보기
Fetch/XHR 필터를 켜고 Content-Type이 application/json인 요청을 찾습니다. Response 탭에서 JSON이 트리 구조로 펼쳐지는 것을 확인합니다.
4. 콘솔에서 직렬화 확인
const note = { id: "n1", title: "제목", createdAt: new Date() };
JSON.stringify(note)createdAt이 Date 객체가 아니라 문자열로 바뀌어 출력되는 것을 확인합니다.
확인
Network탭에서 요청 하나를 골라 메서드·상태 코드·Content-Type을 각각 짚어 말할 수 있습니다.- 콘솔에서
JSON.stringify로Date객체가 문자열로 바뀌는 것을 확인합니다. JSON.parse('{"a":1}')와JSON.parse("{a:1}")(따옴표 없는 키) 중 어느 쪽이 오류가 나는지 확인합니다.
직접 해보기
- 콘솔에서
JSON.stringify({a: undefined, b: 1})을 실행해undefined값을 가진 키가 결과에서 어떻게 되는지 확인해봅니다. notes.seed.json의 메모 객체 하나를 콘솔에 직접 입력하고JSON.stringify(note, null, 2)로 들여쓰기가 적용된 문자열을 만들어봅니다.
정답 보기
JSON.stringify({a: undefined, b: 1})의 결과는 '{"b":1}'입니다. 값이 undefined인 키는 직렬화 과정에서 통째로 사라집니다. JSON.stringify(note, null, 2)처럼 세 번째 인자에 숫자를 넘기면 그 칸 수만큼 들여쓰기가 적용된 읽기 좋은 문자열이 만들어집니다.
자주 하는 실수
| 증상 | 원인 | 고치는 법 |
|---|---|---|
fetch 응답이 400인데도 .then이 정상 실행됨 | fetch는 4xx·5xx도 성공으로 처리한다는 것을 모름 | response.ok(또는 response.status)를 직접 확인 |
JSON.parse 오류 | 문자열 키에 따옴표가 없거나 마지막 항목 뒤에 쉼표가 남음 | JSON 문법(키는 큰따옴표, 마지막 쉼표 없음)을 지킴 |
객체를 그대로 fetch의 body에 넣어 서버가 못 읽음 | JSON.stringify로 직렬화하지 않음 | body: JSON.stringify(note)로 문자열 변환 후 전달 |