REST API(Representational State Transfer API)
클라이언트와 서버 간의 통신을 위한 인터페이스
- 서버 측에서 데이터와 기능을 제공
- 클라이언트 측에서 이를 요청하여 사용
*인터페이스 : 사용자가 쉽게 동작 및 사용하는데 도움을 주는 시스템
*RESTful API : REST API 설계 방식에 맞게 설계한 API
HTTP METHOD
1.GET : 데이터를 읽거나 검색
- 웹사이트를 불러오는 경우도 GET : [네트워크] - [All] 에서 보면 GET으로 대부분 가져오는 걸 볼 수 있음
2. POST : 새로운 리소스를 생성할 때 사용
- 로그인, 게시글 작성 등
- 규정하기 애매한 것들은 POST를 활용한다고 보면 됨
3. PATCH : 일부 데이터를 수정할 때
4. PUT : 보통 전체 데이터를 수정할 때 사용
5. DELETE : 삭제 요청 시 사용
위 METHOD대로 요청을 안 해도 동작은 하지만, RESTful해지지는 않음
올바른 API 설계 방식 (in CSR)
GET, POST, PATCH, DELETE가 전부 사용가능한 환경(CSR)에서의 RESTful API 디자인 방식
1. HTTP METHOD → 동사
2. 설계 URL은 명사 (동작을 안 넣는 것이 좋다)
1. GET : 유저 전체 정보 가져오기
- O : GET /users
- X : GET /user/all/get
2. GET : 특정 유저 조회
- O : GET /users/:id → id에 해당되는 user를 가져온다.
- X : GET /users/:id/get-information
3. POST : 유저 등록
- O : POST /users
- X : POST /user/adduser
4. PATCH : 특정 유저 수정
- O : PATCH /users/:id
- X : PATCH /users/:id/update
5. DELETE : 특정 유저 삭제
- O : DELETE /users/:id
- X : DELETE /users/:id/delete
GET, POST만 가능한 SSR 환경 - HTML 요소 사용
- GET : 링크<a tag>를 클릭하여 URL로 이동하면 GET 요청
- POST : 서버로 데이터를 제출<form tag>하여 처리
GET, POST 이용하기
Pre-setting
1. EC2 인스턴스 활성화
2. local에 DB 연결정보 세팅
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
//AWS EC2 IP
host: "12.34.56.78",
//Mysql 유저 이름
user: "my_sql_id",
// 비밀번호
password: "my_sql_password",
// DB 및 schema 이름
database: "my_database",
// Basic options
waitForConnections: 10,
connectionLimit: 10,
queueLimit: 0
})
module.exports = pool;
3. Express를 이용, EC2에 있는 MySQL 서버 연결
const express = require('express');
const app = express();
const cors = require('cors');
// index 생략 가능
const pool = require('./db/index');
const PORT = 8080;
// app.use 전역 (모든 요청마다 적용)
app.use(cors());
// body에 데이터를 받아오기 위해서는 setting이 꼭 필요함
// json 형식의 데이터를 받아오기 위해 필요한 세팅
app.use(express.json())
// GET /api/menus
// MySQL에 query를 날려 값을 가져올 것
app.get("/api/menus", async(req, res) => {
// db
try {
// pool 가져온 후 진행
const data = await pool.query("select * from menus");
return res.json(data[0]);
}
catch (error) {
console.log(error);
return res.json(error);
}
})
// POST /api/menus
// request.body 안에 있는 menu_name, menu_description을 DB에 query로 날릴 것
app.post("/api/menus", async(req, res) => {
try {
// 1st method : [?] 부분은 변수로 넣을 수 있다. <-- 추천하는 방식
const data = await pool.query(`INSERT INTO menus (menu_name, menu_description)
VALUES (?, ?)`, [req.body.menu_name, req.body.menu_description])
return res.json(data[0]);
// 2nd method : [?] 대신 바로 변수로 넣기
// const data = await pool.query(`
// INSERT INTO menus (menu_name, menu_description)
// VALUES ("${req.body.menu_name}", "${req.body.menu_description}")
// `)
// return res.json(data[0]);
}
catch (error) {
console.log(error);
return res.json(error);
}
});
app.listen(PORT, ()=> console.log(`${PORT} 서버 기동 중`));
4. 임의의 client 생성
// 비동기 처리를 하기 위한 axios 소스 가져오기
const button = document.querySelector("button");
button.addEventListener('click', async function(){
// text 값 받아오는 법
// 1. input_data -> value
// 2. 그 외 html -> textContent
const menu_name = document.querySelector("#menu_name").value;
const menu_description = document.querySelector("#menu_description").value;
// post 요청 보내기
const result = await axios.post("<http://localhost:8080/api/menus>", {
menu_name : menu_name,
// key랑 value가 같으면 생략이 가능
menu_description
})
})
// GET TEST : result가 서버의 log에 찍힘
async function getTest(){
const result = await axios.get("<http://localhost:8080/api/menus>");
console.log(result);
}
getTest();
// POST TEST : result가 서버의 log에 찍힘
async function getPostTest(){
const result = await axios.post("<http://localhost:8080/api/menus>");
console.log(result);
}
getPostTest();
URL 분석
1. Path - params : 로 시작
// id 1 ~ 10까지 다 받아오고 싶은데 일일이 다 작성할 수가 없다.
// ":" 이용 <-- : 로 들어오는 값들은 req.params로 조회가 가능
// GET <http://localhost:8080/api/menus/4> 를 했을 시
app.get("/api/menus/:id", async(req, res) => {
console.log(req.params); // {id : '4'}
console.log(req.params.id); // 4
try {
const data = await pool.query("select * from menus where menu_id = ?",
[req.params.id]);
return res.json(data[0][0]); // menu_id가 4인 record를 가져 옴
}
catch (error) {
console.log(error);
return res.json(error);
}
})
2. Query - query는 ?로 시작
Query vs Params vs Body
query, params
GET, POST, PUT, DELETE, PATCH 때 사용 가능
body // 뒤 쪽에서 다룸
POST PUT PATCH 에서만 가능
Postman
API 개발 및 테스트를 위한 협업 플랫폼, RESTful API 테스트를 위한 다양한 기능들을 포함
사용법
1. GET
// index.js 코드 일부
app.get("/user/:id", async (req, res) => {
try {
return res.json({get_:true, query : req.query, params : req.params});
}
catch (error) {
return res.json({get_:false});
}
})
- 주소창에 local 서버 주소 입력
- 위 화면처럼 SEND 시,
- req.query : Qeury로 넣어 준 KEY, VALUE 값이 저장되어 있음
- req.params : 주소에서 얻은 id의 값이 저장되어 이음
2. POST
app.post("/user", async (req, res) => {
try {
if (req.body.id && req.body.password)
return res.json({signup: true, id: req.body.id, password: req.body.password})
else
return res.json({signup:false});
}
catch (error) {
return res.json({signup:false});
}
})
**[POST]**로 변경 - [Body] 탭 - [raw] 클릭 - [JSON] 으로 변경
이후에 json 형식대로 값을 넣고, send하면 req.body에서 값을 받을 수 있음
Morgan
Node.js 애플리케이션에서 HTTP 요청 로그를 기록하는 데 사용되는 미들웨어
HTTP Response Status Code
- 1xx(Information)
- 요청을 받았으며 프로세스를 진행하는 상태
- 100(요청 후 대기중)
- 2xx(Success)
- 요청을 성공적으로 받았으며 인식했고 진행한 상태
- 200(요청 성공), 201(생성 완료)
- 3xx(Redirection)
- 클라이언트는 요청을 마치기 위해 추가적으로 동작을 취해줘야 한다.
- 301(새위치로 영구적으로 이동), 302(임시이동)
- 4xx(Client Error)
- 클라이언트 단에서 에러가 발생한 경우 해당 오류가 발생한다.
- 400(잘못된 요청), 401(권한 없음), 404(찾을 수 없음)
- 5xx(Server Error)
- 서버 측에 에러가 발생 했을 경우 해당 상태코드가 나타난다. (보통 critical한 issue)
- 500(내부 서버 오류), 503(서버를 사용 할 수 없음), 504(시간 초과)
정적 파일
직접 변화시키지 않는이상 변하지 않는 파일
multer
Node.js에서 파일 업로드를 처리하는 데 사용되는 미들웨어
npm i express morgan multer
클라이언트에서 정적 파일을 서버에 저장하기
// index.js 내용
const express = require("express");
const morgan = require("morgan");
const cors = require("cors");
const multer = require('multer');
const PORT = 8080;
const app = express();
app.use(cors());
app.use(morgan("dev"));
app.use(express.json());
// 정적 서비스
**// '/public' router로 오게 되면, 'public' folder에 있는 정적 파일을 보여 준다는 의미**
// app.use("/public", express.static("public"));
const upload = multer({
// 저장경로 설정
storage: multer.diskStorage({
**// public 경로에 저장할 예정**
destination: (req, file, done) => {
done(null, "public/")
},
**// 저장할 파일 이름 설정**
filename : (req, file, done) => {
done(null, file.originalname); // 원래 이름으로 가져옴
}
}),
// limits: { fileSize: 5 * 1024 * 1024 },
});
// file upload는 무조건 POST
// 무조건 app.use를 거쳐간다. 전역적용 app.use 부분적용
// upload 전 middleware를 거치고 여기로 온다는 의미
// upload.single() : 1개의 파일을 받는다.
app.post("/api/file", upload.single('file'), (req, res) => {
console.log(req.files);
console.log(req.file);
return res.json({test:"OK"});
})
app.listen(PORT, () => console.log("this server listening on " + PORT));
[Body] → [form-data] → [KEY] → [File] 눌러서 진행
중요) KEY 내용이랑, index.js 파일 내 upload.single()의 argument랑 값이 똑같아야 함