Node·Express
JavaScript로 서버 만들기 — Node.js · Express · REST API
CLICK TO OPEN
JavaScript로 서버 만들기 — Node.js · Express · REST API
CLICK TO OPEN
Node·Express · GET·POST · CRUD · 미들웨어 · 풀스택 배포
Node.js
Node.js — 서버에서 JS 실행
Node.js = 브라우저 밖에서 JavaScript를 실행하는 런타임
크롬의 V8 엔진(구글이 만든 JS 실행 엔진)을 떼어내 서버·터미널서도 JS 구동
폴더 구조
코드 — 08_node_express/01_node/index.js
실행
핵심 포인트
왜 Node를 쓰나
• 브라우저 JS는 파일·서버·DB 접근 불가 (보안)
• Node 환경에선 JS로 서버 열기·파일 읽기·DB 저장·API 키 숨김까지 가능
• 결론 — JS로 서버·백엔드 일 하려고 Node 사용 (비유: 브라우저 JS=홀 / Node=주방)
💬 자주 묻는 질문
Node.js랑 브라우저 JavaScript는 같은 거예요?
언어는 똑같은 JS, 실행 장소만 다름 — 브라우저 JS는 화면 꾸미기용, Node는 서버·파일·DB 다루기용
꼭 Node를 설치해야 하나요?
서버·백엔드를 만들 때만 필요 — 브라우저 화면만 만들 땐 없어도 됨
데이터를 만들고·읽고·고치고·지우는(CRUD) 걸 프론트(브라우저)에서 바로 하면 안 되나요? 왜 굳이 서버에서 하나요?
화면에서 흉내는 가능 — 단 새로고침하면 사라지고 내 브라우저에만 남음
진짜 데이터는 DB에 있고, DB·비밀번호·API 키는 서버만 접근 가능
브라우저 코드는 누구나 F12로 열어볼 수 있어 거기 키를 두면 다 털림
→ ① 보안(키·검증 숨김) ② 여러 사람이 같은 데이터 공유 — 이 둘 때문에 CRUD는 서버에서
Express
Express — 웹 서버를 쉽게 만드는 프레임워크
Node 기본 http 모듈만으론 번거로움 → Express가 라우팅·미들웨어를 짧게
가장 널리 쓰는 Node 웹 프레임워크
설치
Express가 해주는 것
• 라우팅 — 주소별 응답 규칙 (app.get·app.post)
• 미들웨어 — 모든 요청 공통 처리 (app.use)
• 요청/응답 다루기 (req·res), 정적 파일 제공, JSON 응답
• 순수 Node http로 다 가능하지만 — Express는 짧고 정해진 방식으로
① 라우트 1개 — 같은 서버 비교
똑같이 "/ 오면 OK, 그 외엔 404" — 코드 양·가독성 비교
Node 최소 서버 코드 (http 모듈)
Express 최소 서버 코드 — 08_node_express/02_express/index.js
• 순수 Node — 주소·메서드 직접 if 분기, 헤더·상태코드 수동, 404도 직접
• Express — app.get 한 줄, 헤더·404 자동
② 라우트 2개 — 차이가 커짐
/ + /about 두 주소 처리
Node 서버 코드 (라우트 2개)
Express 서버 코드 (라우트 2개)
• 순수 Node — 라우트 1개 늘 때마다 else if 한 덩이 추가, 중첩 깊어짐
• Express — app.get 한 줄씩 나란히 → 100개라도 깔끔
• 이게 Express 쓰는 이유 — 라우팅을 대신 처리
핵심 포인트
왜 Express를 쓰나
• 순수 Node는 주소·요청 분기를 직접 if문으로 → 길고 번거로움
• Express는 app.get('/주소') 한 줄로 라우팅
• 같은 서버를 적은 코드·정해진 방식으로 (비유: 순수 Node=맨손 / Express=주방 도구)
용어 정리 — Express는 뭐라 부르나
• 런타임 = 코드 실행 환경 → Node.js
• 프레임워크 = 정해진 틀에 내 코드 끼움 → Express (라이브러리에 가까운 미니멀 프레임워크)
• 프로토콜 = 통신 규칙(약속) → HTTP
• 라이브러리 = 필요할 때 부르는 도구 → axios·lodash 등
한 줄 정리
Node.js(런타임) 위에서 HTTP(프로토콜)로 통신하는 백엔드 서버를, Express(프레임워크)로 쉽게 만듦
💬 자주 묻는 질문
프레임워크가 뭐예요?
자주 쓰는 기능을 미리 만들어둔 도구 모음 — 정해진 틀에 내 코드만 끼우면 동작
npm install express는 매번 해야 하나요?
프로젝트당 1회 — node_modules 폴더에 한 번 깔리면 끝, 새 프로젝트 시작하면 다시 설치
Express 말고 다른 것도 있나요?
Nest·Koa·Fastify 등 있음 — 입문은 가장 많이 쓰는 Express로 충분
최소 서버 구조
최소 서버 구조 — 불러오기 · 라우트 · listen
서버 뼈대 = 불러오기 → 라우트 → listen
라우트 = "이 주소로 오면 이렇게 응답한다"는 규칙
코드 — 08_node_express/03_server/index.js
실행
핵심 포인트
• req — 브라우저가 보낸 요청 / res — 서버가 돌려주는 응답
• listen 없으면 서버 안 켜짐 (문 안 엶)
• 이 뼈대 위에 GET·POST 라우트를 계속 추가
💬 자주 묻는 질문
require('express')는 무슨 뜻이에요?
설치한 express 도구를 이 파일로 꺼내오는 명령 — 꺼내야 app을 만들 수 있음
app은 뭐예요?
express()로 만든 서버 본체 — 여기에 라우트(규칙)를 하나씩 붙여 나감
3000은 무슨 숫자예요?
포트 번호 = 컴퓨터 안의 문 번호 — 다른 숫자(8080 등)도 가능, 같은 번호 겹치면 에러
GET 고정주소
GET ① — 고정 주소 (전체 목록)
GET = 가져오기(조회) — 화면 켜질 때 목록 불러오기
주소가 항상 같음 → 전체 목록 줄 때
전체 코드 — 08_node_express/04_get/index.js
실행
핵심 포인트
• res.json(객체) — 객체/배열을 JSON으로 응답
• 주소 안 변함 → 전체 목록 (글 목록·상품 전체)
• 프론트의 fetch가 부르는 대상이 이 API
💬 자주 묻는 질문
GET이 뭐예요?
데이터를 "가져오기/보기" — 화면 켤 때 목록 불러오는 게 전부 GET
/api/users의 /api는 꼭 붙여야 하나요?
규칙 아닌 관습 — 데이터 주소엔 /api를 붙여 화면 주소와 구분, 안 붙여도 동작은 함
주소창에 직접 쳐도 되나요?
GET은 됨 (브라우저 주소창 = 기본 GET) — localhost:3000/api/users 쳐보면 목록 나옴
GET 변하는주소
GET ② — 변하는 주소 (:param)
주소 끝이 매번 바뀜 → 특정 1개 조회
변하는 자리는 :이름, 값은 req.params로 꺼냄
코드 — 08_node_express/05_get_param/index_users.js
실행
핵심 포인트
• : 붙은 자리 = 변하는 값 / 안 붙으면 고정 주소
• 이름 자유 — :id · :name · :slug, 꺼낼 땐 req.params.그이름 (이름끼리 매칭)
• 용도 — 특정 항목 조회 (프로필 1명·상품 1개·글 1개)
💬 자주 묻는 질문
find가 뭐예요?
배열서 조건 맞는 첫 항목 찾는 JS 함수 — u.id === 3이면 그 유저 1명 반환
찾는 항목이 없으면 어떻게 되나요?
find가 못 찾으면 undefined — 코드에서 404 "없는 유저"로 응답 처리, 안 하면 에러 남
POST 보내기
POST — 데이터 보내기/받기
GET=받아오기 / POST=보내기 — 폼·가입·AI 질문 전부 POST
받을 땐 express.json() 필요
코드 — 받기(서버) · 08_node_express/06_post/index.js
코드 — 보내기(프론트) · 08_node_express/06_post/send.js
Claude 웹도 똑같은 POST
클로드 웹에서 프롬프트 써서 보내기 누름 = 그 글을 body에 담아 POST 전송 → 서버가 답변을 돌려줌
지금 돌린 node send.js와 완전히 같은 왕복 — 주소·body 내용만 다를 뿐
왕복 구조 (모든 웹앱 기본 단위)
프론트 body로 보냄 → 서버 req.body로 꺼냄 → res.json 답장 → 프론트 .then으로 받음
핵심 포인트
• method:'POST' + body 가 핵심 (GET엔 body 없음)
• express.json() 빠지면 req.body undefined
• 보낼 땐 JSON.stringify / 받을 땐 자동 객체
• 프론트 = 보내고(body) + 받고(.then) 왕복
💬 자주 묻는 질문
GET이랑 POST 차이가 뭐예요?
GET = 받아오기(보기) / POST = 보내기(가입·글쓰기·AI 질문) — 짐(body)을 같이 실어 보냄
POST로 보낸 데이터는 주소창에 안 보이나요?
안 보임 — body에 담겨 감 (GET은 주소에 그대로 노출), 그래서 비밀번호·긴 내용은 POST로
headers의 Content-Type은 왜 적어요?
"지금 JSON 보낸다"고 서버에 알리는 꼬리표 — 없으면 서버가 body를 못 알아들을 수 있음
🤝 실습 — 옆 자리 수강생과 주고받기 (LAN)
짝 정하기 — A = 서버(받기) · B = 보내기, 그 다음 역할 바꿔 한 번 더
① A (서버) — node index.js 켜기 → ipconfig 로 IPv4 확인(예 192.168.10.28) → 방화벽 3000 인바운드 허용
② B (보내기) — 주소를 localhost → A의 IP:3000 으로 바꿔 전송
③ 확인 — A 터미널에 받은 메시지: ... 뜨고, B에 답장 { ok: true, 받은문장: ... } → 왕복 성공 🎉
⚠️ 안 되면 순서로 점검 — 둘 다 같은 LAN(192.168.x.x)인지 · 방화벽 3000 열었는지 · IP 오타 · 서버 0.0.0.0 바인딩(app.listen(3000) 기본 OK)
EADDRINUSE 뜨면 3000 이미 사용중 → 데모 포트를 3001 로 (보내는 주소도 :3001)
PUT 수정
PUT — 수정 (Update)
이미 있는 항목을 :id로 찾아 내용 교체
CRUD의 U — Create·Read·Update·Delete
코드 — 08_node_express/08_put_delete/index.js (PUT 부분)
핵심 포인트
• 주소의 :id로 어떤 항목인지 지정
• PUT = 있는 걸 고침 (POST = 새로 추가)
• 없는 id면 404 — find로 확인 후 교체
💬 자주 묻는 질문
CRUD가 뭐예요?
Create(생성)·Read(조회)·Update(수정)·Delete(삭제) 앞글자 — 데이터 다루는 기본 4동작 (POST·GET·PUT·DELETE)
PUT이랑 POST 차이는요?
POST = 새로 추가 / PUT = 이미 있는 걸 고침
DELETE 삭제
DELETE — 삭제 (Delete)
그 :id 항목만 목록에서 빼기
CRUD의 D — Create·Read·Update·Delete
코드 — 08_node_express/08_put_delete/index.js (DELETE 부분)
핵심 포인트
• 주소의 :id로 지울 항목 지정
• filter = 그 id만 빼고 나머지로 새 배열
• DELETE는 보낼 body 없음 → express.json() 불필요
💬 자주 묻는 질문
DELETE는 정말 데이터를 지우나요?
연습은 배열서 빼 진짜 사라짐 — 실무는 '지움 표시'만 남기는 소프트 삭제도 많음(복구·기록용)
GET·POST·PUT·DELETE 4개 합치면요?
게시판 같은 CRUD 완성 — 한 파일서 같은 배열 공유하며 조회·생성·수정·삭제
미들웨어·CORS
미들웨어 · CORS — 공통 처리 ★
app.use = 모든 요청이 거쳐가는 공통 처리 (라우트 위에 둠)
다른 포트끼리 통신하려면 CORS 허용 필요
코드 — 08_node_express/09_middleware/index.js (전체)
동작 흐름
한마디로 (비유)
미들웨어 = 건물 입구의 검색대 🛂
손님(요청)이 사무실(라우트)에 가기 전에 입구를 반드시 통과
• 검색대1 = cors() — 외부 손님 출입 허용
• 검색대2 = express.json() — 가져온 짐(body) 풀어서 정리
• 검색대3 = 내 로그 — 누가 왔는지 장부에 기록
다 통과해야 사무실(app.get/post)에 도착 · 통과 못 시키면(next() 안 부름) 입구서 멈춤
미들웨어가 뭐고 왜 쓰나
미들웨어 = 요청이 라우트(get·post)에 도착하기 전에 먼저 거쳐가는 공통 처리 칸
문제 — 로그 남기기·로그인 확인·CORS 허용은 모든 라우트에 똑같이 필요
→ 라우트마다 복붙하면 코드 길어지고 한 군데 빠뜨리기 쉬움
해결 — app.use로 한 번만 등록하면 모든 요청이 자동으로 거침
좋은 점
• 공통 작업을 한 곳에 모음 = 안 빠지고, 고칠 때 한 곳만
• 위→아래 순서대로 통과 → 인증 실패 시 next() 안 부르고 여기서 바로 차단 가능
• cors()·express.json()처럼 이미 만들어진 미들웨어는 app.use로 등록만 하면 끝 (직접 안 짜도 됨)
CORS 쉽게 정리 (비개발자용)
CORS = 브라우저의 보안 규칙 — 출처(포트·주소)가 다른 곳의 요청은 기본 차단
• 예) 화면(5173) → 서버(3000) = 포트 달라 막힘 → 화면에 데이터 안 옴
• cors() = "다 들여보내" 스위치 — 아무 곳이나 허용 (연습용)
• cors({ origin: '내주소' }) = 내 사이트만 허용 — 아무나 못 쓰게 막음 (실무·보안)
• 출처 = 프로토콜+주소(도메인·IP)+포트가 통째로 같아야 같은 곳 (하나만 달라도 남)
• 안 쓰면 → 화면 fetch가 빨간 에러로 차단
• curl·Postman은 브라우저가 아니라 CORS 영향 없음 (그래서 curl 테스트는 cors 없이도 됨)
핵심 포인트
• 실무에선 대부분 cors()·express.json()를 app.use로 등록해 씀 (직접 만드는 일은 드묾)
• CORS 빠지면 React fetch 빨간 에러로 차단
• express.json() 빠지면 req.body undefined
• 미들웨어는 라우트보다 위에 둬야 함 (위→아래 순서)
express.json() 변환 전 → 후
💬 자주 묻는 질문
미들웨어를 여러 개 쓸 수 있나요?
가능 — app.use를 여러 줄 쌓으면 위에서부터 차례로 실행(cors → json → 로그 …)
특정 주소에만 미들웨어를 걸 수 있나요?
가능 — app.use('/api', 함수)처럼 경로를 주면 그 경로로 온 요청만 거침
req, res, next 이 세 개는 각각 뭐예요?
req = 들어온 요청 정보 / res = 응답 보내는 도구 / next = 다음 단계로 넘기는 스위치
미들웨어랑 라우트(app.get)는 뭐가 달라요?
미들웨어 = 모든 요청이 거쳐가는 공통 처리 / 라우트 = 특정 주소에만 응답
CRUD실습
우리 반 배치도 만들기 — CRUD 최종 과제 ★
강사 서버에서 20명 학생 데이터 → fetch + CRUD → HTML 배치도 완성
① 강사 서버 정보
서버 주소: http://192.168.10.28:5000
엔드포인트: /hancom/:반이름/users
토큰: HANCOM (Authorization 헤더 필수)
데이터: 수강생 (오염된 상태)
② 우리 반 정상 명단 (20명)
강성원 · 강하영 · 김정아 · 김정현 · 김해냄 · 김효인 · 박진 · 안치호 · 양하은 · 유민성 · 이도연 · 이현우 · 임소정 · 전욱진 · 정기준 · 정선민 · 정유진 · 표후동 · 한유진 · 한윤지
③ 문제 상황 — 서버 데이터가 오염됨
강사 서버의 데이터는 정상 상태가 아님. 일부 이름이 잘못됨, 중복됨, 누락됨, 또는 불필요한 이름이 추가됨.
해야 할 일:
1. fetch로 현재 서버 데이터 조회
2. 정상 명단(위)과 비교
3. PUT으로 수정, DELETE로 삭제, POST로 추가
결과: 서버의 수강생 리스트를 정확히 수정 + HTML 배치도로 표시
④ fetch로 데이터 조회 (예제)
⑤ CRUD API 정보
GET /hancom/:반이름/users = 20명 조회POST /hancom/:반이름/users = 학생 추가PUT /hancom/:반이름/users/:id = 학생 정보 수정DELETE /hancom/:반이름/users/:id = 학생 삭제
모든 요청 시 Authorization: HANCOM 헤더 필수
🎯 최종 과제 — 우리 반 배치도 완성
1단계: 자신의 반 이름으로 fetch 요청 → 20명 학생 데이터 조회
2단계: 받은 학생 배열을 HTML 그리드로 배치도 표시 (예: 4열 5행)
3단계: 이름 클릭 → prompt로 새 이름 입력 → PUT으로 수정 기능
4단계: POST로 21번째 학생 추가 가능
5단계: DELETE로 학생 삭제 기능
강사 서버에서 모든 CRUD 로그는 자동 기록됨. 강사가 /logs/:반이름으로 조회 가능
💬 자주 묻는 질문
Authorization 헤더는 어디에 넣나요?
fetch 옵션에: { headers: { 'Authorization': 'HANCOM' } }
배치도는 어떤 디자인으로 해야 하나요?
자유. HTML grid/flex로 4열 5행 좌석 표처럼 표현하거나, 원탁 배치 등 자유로운 형식 가능