📌 Express API
클라이언트의 요청 경로(URL)에 따라 작업을 처리하고 응답을 반환하는 Node.js 프레임워크
간단한 코드로 요청 경로와 핸들러를 연결하여 API 서버 구축에 적합합니다.
🗂️ Express API 서버 구축
⭕ 터미널 열기 : Ctrl + Shift + `
❌ 터미널 프로세스 종료 : Ctrl + C
✅ 프로젝트 초기화
새로운 Node.js 프로젝트 생성
-y 옵션은 기본 설정으로 '📜package.json' 파일' 을 생성합니다.
npm init -y
'📜package.json' 파일 스크립트 추가
"scripts": {
"start": "node server.js",
},
✅ Express 설치
Express는 API 서버를 간단히 구축할 수 있는 Node.js 프레임워크입니다.
npm i express
⚙️ server.js 서버 파일 생성
Express 애플리케이션을 초기화하고 서버를 실행합니다.
- 기본 라우팅 : 단일 변수를 사용해 요청 처리
- 중첩 라우팅 : 여러 동적 변수를 사용해 요청 처리
- req.params : URL 경로에서 동적 변수 값을 추출하는 객체
- 포트 설정 : 서버는 9999번 포트에서 실행
// ▶ ⚙️server.js
// 🌐http://localhost:9999
const express = require('express');
const app = express();
app.listen(9999);
🔎 기본 라우팅 (Path Parameter)
기본 라우팅은 단일 경로 변수(:id)를 사용하여 요청 처리
- GET 요청 : http://localhost:9999/board/30
- 서버 응답 : { "boardID": "30" }
// ▶ ⚙️server.js
const express = require('express');
const app = express();
app.get('/board/:id', (req, res) => {
const { id } = req.params; // 경로에서 'id' 변수 추출
res.status(200).send({
boardID: id // 응답 데이터에 'id' 포함
});
});
app.listen(9999);
🔎 중첩 라우팅
중첩 라우팅은 여러 동적 변수(:id, :pw, :name)를 사용하여 요청 처리
- GET 요청 : http://localhost:9999/board/thgus/1234/권소현
- 서버 응답 : { "boardID":"thgus", "pw":"1234", "name":"권소현" }
// ▶ ⚙️server.js
const express = require('express');
const app = express();
app.get('/board/:id/:pw/:name', (req, res) => {
const { id, pw, name } = req.params; // 경로에서 'id', 'pw', 'name' 변수 추출
res.status(200).send({
boardID: id, // 'id' 값 포함
pw, // 'pw' 값 포함
name // 'name' 값 포함
});
});
app.listen(9999);
➕ Path Parameter VS Query String 비교
Express에서는 데이터를 URL 경로로 전달하는 두 가지 주요 방식이 있습니다.
방식 | 설명 | 예시 |
Path Parameter | 경로 일부를 변수처럼 사용 ➡️ 특정 리소스를 식별할 때 사용 |
/users/:id ➡️ /users/123 |
Query String | URL 뒤에 키-값 쌍으로 전달 ➡️ 필터링/정렬 같은 부가 정보를 전달할 때 사용 |
/search?keyword=express |
// ➡️ Path Parameter
/* - 요청 : GET /users/1
- 응답 : User ID: 1
*/
app.get('/users/:id', (req, res) => {
const userId = req.params.id; // Path Parameter에서 ID 추출
res.send(`User ID: ${userId}`);
});
// ➡️ Query String
/* - 요청 : GET /search?keyword=express
- 응답 : 검색 키워드: express
*/
app.get('/search', (req, res) => {
const keyword = req.query.keyword; // Query String에서 키워드 추출
res.send(`검색 키워드: ${keyword}`);
});
사용예시
// ▶ ⚙️server.js
// 🌐http://localhost:9999
// 1️⃣Express 모듈 로드
const express = require('express');
// 2️⃣Express 애플리케이션 객체 생성
const app = express();
// 3️⃣기본 라우팅
app.get('/board/:id', (req, res) => {
const { id } = req.params;
res.status(200).send({ boardID: id });
});
// 4️⃣중첩 라우팅
app.get('/board/:id/:pw/:name', (req, res) => {
const { id, pw, name } = req.params;
res.status(200).send({
boardID: id,
pw,
name,
});
});
// 5️⃣서버 실행
app.listen(9999, () => {
console.log('Server is running on http://localhost:9999');
});
✅ 서버 실행
🌐 http://localhost:9999
npm start
📌 Express 라우트 구조
Express에서 라우트는 클라이언트의 요청을 받고 처리한 후 응답을 보내는 역할
- app : Express 애플리케이션 인스턴스
- METHOD : HTTP 요청 메서드(GET, POST, PUT, DELETE 등)
- PATH : 클라이언트가 요청할 경로
- HANDLER : 요청을 처리하고 응답을 반환하는 함수(콜백)
app.METHOD(PATH, HANDLER);
사용예시
- app.get : 클라이언트의 GET 요청 처리
- '/' : 루트 경로(기본 홈페이지)
- res.send : 응답으로 메시지 보내기("Hello World!" 응답 반환)
app.get('/', (req, res) => {
res.send('Hello World!');
});
📌 HTTP 메서드 VS RESTful API
Express에서는 HTTP 메서드를 사용하여 클라이언트 요청을 처리합니다.
RESTful API 설계는 클라이언트-서버 간의 데이터 통신을 효율적으로 처리할 수 있도록 설계된 표준
🔎 HTTP 메서드와 역할
메서드 | 설명 | 예시 |
GET | 데이터 조회 | GET /users |
POST | 새로운 데이터 생성 | POST /users |
PUT | 기존 데이터 전체 수정 | PUT /users/:id |
PATCH | 기존 데이터 부분 수정 | PATCH /users/:id |
DELETE | 데이터 삭제 | DELETE /users/:id |
🔎 RESTful API 설계 원칙
- 리소스 기반 경로
- 데이터를 명사 형태 표현
예 : /users, /products - HTTP 메서드 동작 정의
- 생성(POST) / 조회(GET) / 수정(PUT) / 삭제(DELETE) 사용 - 계층적 경로 설계
- 데이터 관계를 계층적으로 표현
예 : /users/1/orders (ID 1 사용자의 주문 목록)
// ➡️ 전체 조회
app.get('/users', (req, res) => res.json([]));
// ➡️ 새 사용자 생성
app.post('/users', (req, res) => res.send('새 사용자 생성'));
// ➡️ 사용자 수정
app.put('/users/:id', (req, res) => res.send(`User ${req.params.id} 수정`));
// ➡️ 사용자 삭제
app.delete('/users/:id', (req, res) => res.send(`User ${req.params.id} 삭제`));
📌 Express 라우트 경로 설정
Express에서는 라우트 경로를 정의하여 클라이언트 요청을 처리합니다.
라우트 경로는 문자열, 패턴, 또는 정규식으로 정의할 수 있습니다.
- 문자열 경로 : 요청 경로가 정확히 일치
- 문자열 패턴 : 특정 문자 패턴 일치
- 정규식 경로 : 복잡한 경로 패턴 처리
🔎 문자열 경로
가장 간단한 형태로, 경로를 문자열로 정의합니다.
요청 경로가 정확히 일치해야 핸들러가 실행됩니다.
- GET / ➡️ 홈 화면
- GET /about ➡️ 소개 페이지
- GET /about/customer ➡️ 고객 소개 페이지
// '/', '/about', '/about/customer'
app.get('/', (req, res) => res.send('홈 화면'));
app.get('/about', (req, res) => res.send('소개 페이지'));
app.get('/about/customer', (req, res) => res.send('고객 소개 페이지'));
🔎 문자열 패턴 경로
특정 패턴을 정의하여 유연하게 경로를 처리할 수 있습니다.
- GET /acd ➡️ b가 0개 또는 1개 포함
- GET /abcd ➡️ b가 1개 이상 포함
- GET /ab123cd ➡️ ab와 cd 사이에 문자 포함
- GET /abe ➡️ cd가 0개 또는 1개 포함
패턴 | 설명 | 예시 |
/ab?cd | 문자 b가 0개 또는 1개 포함 ➡️ ? 해당문자 0개 또는 1개 포함 |
/acd /abcd |
/ab+cd | 문자 b가 1개 이상 포함 ➡️ + 해당문자 1개 이상 포함 |
/abcd /abbcd |
/ab*cd | ab와 cd 사이에 문자 0개 이상 포함 ➡️ * 해당문자 0개 이상 포함 |
/abcd /ab123cd /abXYZcd |
/ab(cd)?e | 문자 cd가 0개 또는 1개 포함 ➡️ ()? 그룹이 0개 또는 1개 포함 |
/abe /abcde |
app.get('/ab?cd', (req, res) => res.send('b가 0개 또는 1개 포함'));
app.get('/ab+cd', (req, res) => res.send('b가 1개 이상 포함'));
app.get('/ab*cd', (req, res) => res.send('ab와 cd 사이에 문자 포함'));
app.get('/ab(cd)?e', (req, res) => res.send('cd가 0개 또는 1개 포함'));
🔎 정규식 경로
정규 표현식(Regex) 사용하여 복잡한 경로를 정의
정규식은 패턴 일치를 확인하며, 경로가 일치하면 핸들러가 실행됩니다.
- GET /abc ➡️ 경로에 a가 포함됨
- GET /123a456 ➡️ 경로에 a가 포함됨
- GET /insert123 ➡️ insert로 시작하는 경로
정규식 | 설명 | 예시 |
/a/ | 경로에 문자 a가 포함된 경우 | /abc /123a456 |
/^insert/ | 경로가 insert로 시작하는 경우 | /insert /insert123 |
app.get(/a/, (req, res) => res.send('경로에 a가 포함됨'));
app.get(/^insert/, (req, res) => res.send('insert로 시작하는 경로'));
사용예시
const express = require('express');
const app = express();
// ▶ 문자열 경로
app.get('/', (req, res) => res.send('홈 화면'));
app.get('/about', (req, res) => res.send('소개 페이지'));
app.get('/about/customer', (req, res) => res.send('고객 소개 페이지'));
// ▶ 문자열 패턴 경로
app.get('/ab?cd', (req, res) => res.send('b가 0개 또는 1개'));
app.get('/ab+cd', (req, res) => res.send('b가 1개 이상'));
app.get('/ab*cd', (req, res) => res.send('ab와 cd 사이에 문자 포함'));
app.get('/ab(cd)?e', (req, res) => res.send('cd가 0개 또는 1개'));
// ▶ 정규식 경로
app.get(/a/, (req, res) => res.send('경로에 a가 포함됨'));
app.get(/^insert/, (req, res) => res.send('insert로 시작하는 경로'));
// 서버 실행
app.listen(3000, () => console.log('서버 실행 중: http://localhost:3000'));
📌 Express 다중 핸들러
Express에서 다중 핸들러는 하나의 요청에 대해 여러 작업을 단계적으로 처리
각 핸들러는 요청(req)과 응답(res) 객체를 다루며, next()를 호출해 다음 핸들러로 흐름 전달
핸들러는 3개의 주요 매개변수를 사용합니다.
- req : 클라이언트 요청(Request) 객체
- res : 서버 응답(Response) 객체
- next : 다음(Next) 미들웨어 또는 핸들러로 넘어가게 하는 함수
🔎 하나의 요청에 여러 핸들러 사용
next()를 사용하여 요청 처리 흐름을 다음 핸들러로 넘길 수 있습니다.
- 첫 번째 핸들러 : 실행 후 console.log()로 메시지 출력
- next() 호출 : 두 번째 핸들러로 요청 흐름 전달
- 두 번째 핸들러 : res.send()를 사용해 응답을 전송하며 요청 처리 완료
app.get('/example', (req, res, next) => {
console.log('첫 번째 핸들러 실행');
// ▶ 다음 핸들러 호출
next();
}, (req, res) => {
res.send('두 번째 핸들러 실행'); // 클라이언트에게 응답 전송
});
🔎 콜백 함수 배열 사용
핸들러를 배열로 정의하여 요청 처리를 단계적으로 나눌 수 있습니다.
이를 통해 코드 재사용성과 가독성을 높일 수 있습니다.
- handler1 실행 ➡️ 메시지 출력 후 next()로 handler2 호출
- handler2 실행 ➡️ 메시지 출력 후 next()로 handler3 호출
- handler3 실행 ➡️ 클라이언트에게 응답 전송(res.send())
const handler1 = (req, res, next) => {
console.log('첫 번째 핸들러');
next(); // 다음 핸들러 호출
};
const handler2 = (req, res, next) => {
console.log('두 번째 핸들러');
next(); // 다음 핸들러 호출
};
const handler3 = (req, res) => {
res.send('세 번째 핸들러에서 응답 전송');
};
// ▶ 핸들러 배열로 정의
app.get('/example', [handler1, handler2, handler3]);
사용예시
const express = require('express');
const app = express();
// ▶ 핸들러 정의
const handler1 = (req, res, next) => {
console.log('첫 번째 핸들러 실행');
next();
};
const handler2 = (req, res, next) => {
console.log('두 번째 핸들러 실행');
next();
};
const handler3 = (req, res) => {
res.send('세 번째 핸들러에서 응답 전송');
};
// ▶ '/example' 경로에서 다중 핸들러 실행
app.get('/example', [handler1, handler2, handler3]);
// 서버 실행
app.listen(3000, () => console.log('서버 실행 중: http://localhost:3000'));
📌 Express 응답 메서드
Express에서 응답 메서드는 서버가 클라이언트 요청에 응답할 때 사용
클라이언트에게 데이터를 전송하거나 작업 완료 상태를 알릴 수 있습니다.
응답 메서드
|
설명
|
예시
|
res.download()
|
클라이언트에 파일 다운로드 프롬프트 전송 |
res.download(
'/path/to/file' ) |
res.end()
|
응답 프로세스 종료
|
res.end()
|
res.json()
|
JSON 데이터를 응답으로 전송 |
res.json(
{ message: 'Hello, JSON!' } ) |
res.jsonp()
|
JSONP 형식으로
JSON 데이터를 응답 |
res.jsonp(
{ message: 'Hello, JSONP!' } ) |
res.redirect()
|
클라이언트를 지정된 경로로 리다이렉트 |
res.redirect(
'/new-path' ) |
res.render()
|
뷰 템플릿을 렌더링하여
HTML로 응답 |
res.render(
'index', { title: 'My Page' } ) |
res.send()
|
문자열, 객체, HTML 등 다양한 데이터를 응답 |
res.send(
'<h1>Hello, World!</h1>' ) |
res.sendFile()
|
지정된 파일 데이터를
클라이언트에 전송 |
res.sendFile(
'/path/to/image.jpg' ) |
res.sendStatus()
|
HTTP 상태 코드를 설정하고
메시지를 응답 |
res.sendStatus(
404 ) |
사용예시
const express = require('express');
const app = express();
// ▶ JSON 데이터 응답
app.get('/json', (req, res) => {
res.json({ message: 'Hello, JSON!' }); // JSON 데이터 전송
});
// ▶ 파일 다운로드
app.get('/download', (req, res) => {
res.download('./files/example.txt'); // example.txt 파일 다운로드
});
// ▶ 리다이렉트
app.get('/old-path', (req, res) => {
res.redirect('/new-path'); // 클라이언트를 /new-path로 이동
});
// ▶ 텍스트 응답
app.get('/text', (req, res) => {
res.send('Hello, World!'); // 텍스트 응답
});
// ▶ 상태 코드 응답
app.get('/not-found', (req, res) => {
res.sendStatus(404); // 404 Not Found 상태 코드 응답
});
// 서버 실행
app.listen(3000, () => {
console.log('서버 실행 중: http://localhost:3000');
});
📌 Express 라우트 관리
Express에서는 라우트 처리를 통해 클라이언트 요청을 처리하고 응답을 보냅니다.
app.route()와 express.Router()를 활용하면 효율적이고 체계적인 라우트 관리가 가능합니다.
🔎 라우트 관리 방식
app.route()
- 한 경로에서 여러 HTTP 메서드 처리
- 간단한 라우트에 적합
express.Router()
- 라우트를 파일로 분리해 모듈화
- 큰 프로젝트나 복잡한 라우트 구조에 유용
- 코드 가독성과 유지보수성을 크게 향상
특징 | app.route() | express.Router() |
사용 목적 | 한 경로에서 여러 HTTP 메서드 처리 | 라우트를 파일로 분리하고 모듈화 |
적합한 상황 | 간단한 라우트 처리 | 대규모 프로젝트나 복잡한 구조 |
코드 재사용성 | 낮음 | 높음 |
코드 가독성 | 간단한 라우트에서 높음 | 모듈화된 구조에서 높음 |
🔎 app.route()
하나의 경로에서 여러 HTTP 메서드 처리(GET, POST, PUT, DELETE 등)
app.route('/customer')
.get((req, res) => res.send('고객 정보 조회')) // GET 요청 처리
.post((req, res) => res.send('신규 고객 추가')) // POST 요청 처리
.put((req, res) => res.send('고객 정보 수정')) // PUT 요청 처리
.delete((req, res) => res.send('고객 정보 삭제')); // DELETE 요청 처리
🔎 express.Router()
라우트를 여러 파일로 분리하여 관리
이 방식은 라우트가 많아질 때 코드 가독성과 유지보수성을 크게 향상시킵니다.
사용예시
📜 routes/customer.js
// ▶ 📜routes/customer.js
const express = require("express");
const router = express.Router();
router
.get("/", (req, res) => res.send("고객 정보 조회")) // GET 요청
.post("/insert", (req, res) => res.send("신규 고객 추가")) // POST 요청
.put("/update", (req, res) => res.send("고객 정보 수정")) // PUT 요청
.delete("/delete", (req, res) => res.send("고객 정보 삭제")); // DELETE 요청
module.exports = router;
📜 routes/product.js
// ▶ 📜routes/product.js
const express = require("express");
const router = express.Router();
router
.get("/", (req, res) => res.send("상품 정보 조회")) // GET 요청
.post("/insert", (req, res) => res.send("신규 상품 추가")) // POST 요청
.put("/update", (req, res) => res.send("상품 정보 수정")) // PUT 요청
.delete("/delete", (req, res) => res.send("상품 정보 삭제")); // DELETE 요청
module.exports = router;
📜 app.js
express.Router로 분리한 라우트를 app.js에서 불러와 사용합니다.
// ▶ 📜app.js
const express = require('express');
const customerRoute = require('./routes/customer'); // customer 라우트 추가
const productRoute = require('./routes/product'); // product 라우트 추가
const app = express();
// 1️⃣JSON 요청 파싱
app.use(express.json({ limit: '50mb' })); // 요청 본문 최대 50MB
// 2️⃣라우트 연결
app.use('/customer', customerRoute); // /customer 경로에 customer 라우트 연결
app.use('/product', productRoute); // /product 경로에 product 라우트 연결
// 3️⃣서버 실행
app.listen(3000, () => {
console.log('Server started on http://localhost:3000');
});
'📌 Front End > └ Node.js' 카테고리의 다른 글
[Node.js] Nodejs 모듈(CommonJS / ES Modules) (0) | 2024.08.09 |
---|---|
[Node.js] Package.json 명령어 npm start, npm run build 스크립트 차이점 (1) | 2024.08.09 |
[Node.js] Package.json 패키지 관리 (3) | 2024.08.09 |
[Node.js] Node 개념 및 기본 명령어 (0) | 2024.08.09 |