๐๐ป GET,POST,PATCH,PUT์ axios๋ชจ๋์ ์ฌ์ฉํ์ฌ ๊ตฌํํ ์ฝ๋์
๋๋ค.
This is the code that implements GET, POST, PATCH, and PUT using the axios module.
๐๐ป ํ๋ก์ ํธ ์์ฑ๊ณผ ๋ชจ๋ ์ค์น๋ ์ด์ ํฌ์คํธ๋ฅผ ์ฐธ์กฐํ์ธ์
Please refer to the previous post for project creation and module installation.
๐๐ป ๋ธ๋ผ์ฐ์ ์์ ์ฐจ๋จ๋๋ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ์ง ์ํด์ cors๋ชจ๋๋ ์ค์นํฉ๋๋ค.
Also install the cors module to avoid browser blocking errors.
๐๐ป CORS
โ๏ธ ๋ชจ๋์ค์น / Module installation
% npm install cors
โ๏ธCORS๋ Cross-Origin Resource Sharing์ ์ค์๋ง์
๋๋ค.
CORS stands for Cross-Origin Resource Sharing.
โ๏ธ ๋ธ๋ผ์ฐ์ ๋ ๋ณด์์ ์ด์ ๋ก ๋ค๋ฅธ ์ถ์ฒ(๋๋ฉ์ธ, ํฌํธ, ํ๋กํ ์ฝ)๊ฐ ๋ค๋ฅธ ์๋ฒ์ ์์ฒญํ๋ ๊ฒ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฐจ๋จํฉ๋๋ค.
For security reasons, browsers block requests from other origins (domains, ports, protocols) to other servers by default.
โ๏ธ ์๋ฅผ ๋ค์ด ํ๋ก ํธ์๋: http://localhost:3000 ,๋ฐฑ์๋: http://localhost:5000 ์ด ๊ฒฝ์ฐ ํฌํธ๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ์ถ์ฒ๋ก ์ธ์๋์ด ์์ฒญ์ด ์ฐจ๋จ๋ฉ๋๋ค.
For example, frontend: http://localhost:3000, backend: http://localhost:5000 In this case, since the ports are different, the requests are recognized as different origins and blocked.
โ๏ธ ๊ทธ๋์ ๋ธ๋ผ์ฐ์ ์ ์ฃผ์์ ๋ฐฑ์๋ ์๋ฒ์ ์ฃผ์๊ฐ ๋ค๋ฅด๋ฉด ๋ฐฑ์๋ ์๋ฒ์์ ํ์ฉ์ ํด์ค์ผํฉ๋๋ค.
So, if the browser address and the backend server address are different, you need to allow it on the backend server.
โ๏ธ ์ฐจ๋จ์ ๋ธ๋ผ์ฐ์ ์์ ํ์ง๋ง ๋ฐฑ์๋ ์๋ฒ์ cors๋ชจ๋์ ์ค์นํ๊ฒฝ์ฐ ๋ธ๋ผ์ฐ์ ์์ ์์ฒญ์ ์๋ฒ์์ ํค๋์ ๋ณด๋ฅผ ๋ธ๋ผ์ฐ์ ๋ก ๋ฆฌํดํ๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ฉํฉ๋๋ค.
Blocking is done in the browser, but if the CORS module is installed on the backend server, the browser allows it when the server returns header information to the browser when making a request.
โ๏ธ ์๋์ App.tsx์์๋ ๋ค์์ฒ๋ผ cors๋ชจ๋์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
In the App.tsx below, we are using the cors module as follows:
const cors = require("cors");
app.use(cors());
๐๐ป axios
โ๏ธ ๋ชจ๋์ค์น / Module installation
npm install axios
โ๏ธ axios๋ HTTP ์์ฒญ์ ์ฝ๊ฒ ๋ณด๋ด๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์
๋๋ค.
Axios is a library that makes it easy to send HTTP requests.
โ๏ธ promise๊ธฐ๋ฐ์ด๋ฉฐ .then() / .catch() ๋๋ async/await ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
It is promise-based and can use .then() / .catch() or async/await.
โ๏ธ JSON์ ์๋ ๋ณํํฉ๋๋ค.
Automatically converts JSON.
โ๏ธ ์์ฒญ์๋ต๊ฐ๋ก์ฑ๊ธฐ๋ฅผ ํ ์ ์์ต๋๋ค.
You can intercept request responses.
— ์ฌ๊ธฐ์๋ ์ฌ์ฉํ์ง ์์ผ๋ฉฐ refreshToken,accessToken์ ์ฌ์ฉํ์ฌ ์ธ์ฆ ํ ๊ฒฝ์ฐ ์ฌ์ฉํฉ๋๋ค.
It is not used here, but is used when authenticating using refreshToken and accessToken.
— ์๋์ ํ์์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
Use the format below.
axios.interceptors.request.use(config => {
config.headers.Authorization = "Bearer token";
return config;
});
โ timeout ์ค์ ์ด ๊ฐ๋ฅํฉ๋๋ค.
Timeout setting is possible.
— ์ฌ๊ธฐ์๋ ์ฌ์ฉํ์ง ์์ต๋๋ค.
Not used here.
axios.get("/api", { timeout: 5000 });
โ๏ธ ์๋์ App.tsx(ํ๋ก ํธ์๋) ์ฝ๋์ axios๋ชจ๋์ ์ฌ์ฉํด์ vite.config.ts๋์ ์ ๋ค์ ์ค์ ์ ์ฌ์ฉํฉ๋๋ค.
In the server.js (frontend) code below, use the axios module and use the following configuration instead of vite.config.ts.
โ๏ธ ์๋์ App.tsx์์ ๋์ ๋ผ์ฐํฐ ์ฌ์ฉ์ ์ํด์ ์ค์ ํฉ๋๋ค.(vite.config.ts์ ๋์ผํ ์ญํ )
Configure the App.tsx below to use a dynamic router. (Same role as vite.config.ts)
const api = axios.create({
baseURL: "http://localhost:3000",
});
๐๐ป ํ๋ก ํธ์๋ / Front-end
โ๏ธ App.tsx
import React, { useState } from "react";
import axios from "axios";
function UserComponent() {
const [userId, setUserId] = useState("1");
const [userData, setUserData] = useState(null);
const [log, setLog] = useState("");
// vite.config.ts ๋์ ์ค์ ํ ์ ์์.
// ๋์ ์ cors์๋ฌ๊ฐ ๋ฐ์ํ ์ ์์ผ๋ ๋ฐ๋์ ์๋ฒ์ชฝ์ cors๋ชจ๋ ์ค์น ํ ๊ฒ
// You can set it instead of vite.config.ts.
// Instead, you must install the cors module on the server side to avoid a cors error.
const api = axios.create({
baseURL: "http://localhost:3000",
});
const handleResponse = (res) => {
setUserData(res.data || null);
setLog(JSON.stringify(res.data, null, 2));
};
const handleError = (err) => {
const data = err.response?.data || { message: "Error occurred" };
setUserData(null);
setLog(JSON.stringify(data, null, 2));
};
const getUser = () =>
api.get(`/users/${userId}`).then(handleResponse).catch(handleError);
const createUser = () =>
api
.post("/users", {
name: "NewUser",
age: 30,
nickname: "SilverHand",
})
.then(handleResponse)
.catch(handleError);
const patchUser = () =>
api
.patch(`/users/${userId}`, {
nickname: "Johnny",
})
.then(handleResponse)
.catch(handleError);
const putUser = () =>
api
.put(`/users/${userId}`, {
name: "John",
age: 25,
})
.then(handleResponse)
.catch(handleError);
const deleteUser = () =>
api
.delete(`/users/${userId}`)
.then((res) => {
setUserData(null);
setLog(res.data.message);
})
.catch(handleError);
return (
<div style={{ padding: "20px", fontFamily: "sans-serif" }}>
<h1>HTTP Methods Playground</h1>
<input
value={userId}
onChange={(e) => setUserId(e.target.value)}
placeholder="User ID"
/>
<div style={{ margin: "10px 0", display: "flex", gap: "10px" }}>
<button onClick={getUser}>GET</button>
<button onClick={createUser}>POST</button>
<button onClick={patchUser}>PATCH</button>
<button onClick={putUser}>PUT</button>
<button onClick={deleteUser}>DELETE</button>
</div>
<div
style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "20px" }}
>
<section>
<h3>ํ์ฌ ๋ฐ์ดํฐ ์์ธ/Current data details</h3>
{userData ? (
<div style={{ border: "1px solid blue", padding: "10px" }}>
<p>ID: {userData.id}</p>
<p>์ด๋ฆ/Name: {userData.name || "์์"}</p>
<p>๋์ด/Age: {userData.age || "์์"}</p>
<p>๋๋ค์/NickName: {userData.nickname || "์์"}</p>
</div>
) : (
<p>์กฐํ๋ ๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค./Detailed search of current data.</p>
)}
</section>
<section>
<h3>์๋ฒ์๋ต/Server response</h3>
<pre style={{ background: "#f4f4f4", padding: "10px" }}>{log}</pre>
</section>
</div>
</div>
);
}
export default UserComponent;
๐๐ป ๋ฐฑ์๋ / Back-end
const express = require("express");
const app = express();
const cors = require("cors");
const PORT = 3000;
// ์๋ฒ์ ์์ฒญํ๋ ๊ณณ์ ํฌํธ๊ฐ ๋ค๋ฅด๋ฉด cors์๋ฌ ๋ฐ์ํจ.
// ํฌํธ๊ฐ ๋ค๋ฅด๋ฉด ๋ธ๋ผ์ฐ์ ๋ ๋ค๋ฅธ ์ถ์ฒ(origin) ๋ก ํ๋จํจ.
// ๋ธ๋ผ์ฐ์ ๋ณด์์ ์ฑ
์ ํ๋กํ ์ฝ,๋๋ฉ์ธ,ํฌํธ๋ฒํธ์ค ํ๋๋ผ๋ ํ๋ฆฌ๋ฉด ๋ง์.
// If the port of the server and the requesting party are different, a CORS error occurs.
// If the ports are different, the browser considers them to be from different origins.
// According to browser security policy, if any of the protocol, domain, or port number is different, the request is blocked.
app.use(cors());
app.use(express.json());
// ๊ฐ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค / Virtual Database
let users = [{ id: "1", name: "V", age: 20, nickname: "Cyberpunk2077" }];
// GET: ํน์ ์ ์ ์กฐํ / Specific user inquiry
app.get("/users/:id", (req, res) => {
const user = users.find((u) => u.id === req.params.id);
user
? res.json(user)
: res.status(404).json({ message: "์ ์ ์์/No user" });
});
// POST: ์๋ก์ด ์ ์ ์์ฑ / Create new user
app.post("/users", (req, res) => {
const newUser = { id: String(users.length + 1), ...req.body };
users.push(newUser);
res.status(201).json(newUser);
});
// PATCH: ๋ฐ์ดํฐ์ '์ผ๋ถ'๋ง ์์ (๊ธฐ์กด ๋ฐ์ดํฐ ์ ์ง)
// Modify only 'part' of the data (keep existing data)
app.patch("/users/:id", (req, res) => {
const index = users.findIndex((u) => u.id === req.params.id);
if (index !== -1) {
// ๊ธฐ์กด ๊ฐ + ๋ฐ๋ ๊ฐ ํฉ์น๊ธฐ / Merge existing value + changed value
users[index] = { ...users[index], ...req.body };
res.json(users[index]);
} else {
res.status(404).json({ message: "์ ์ ์์/No user" });
}
});
// PUT: ๋ฐ์ดํฐ '์ ์ฒด'๋ฅผ ๊ต์ฒด (๋ณด๋ด์ง ์์ ํ๋๋ ์ฌ๋ผ์ง)
// Replace 'all' data (unsent fields disappear)
app.put("/users/:id", (req, res) => {
const index = users.findIndex((u) => u.id === req.params.id);
if (index !== -1) {
// ๊ธฐ์กด ๋ด์ฉ ๋ฌด์ํ๊ณ ๋ฎ์ด์ฐ๊ธฐ / Ignore existing content and overwrite
users[index] = { id: req.params.id, ...req.body };
res.json(users[index]);
} else {
res.status(404).json({ message: "์ ์ ์์/No user" });
}
});
// DELETE: ๋ฐ์ดํฐ ์ญ์ / data deletion
app.delete("/users/:id", (req, res) => {
users = users.filter((u) => u.id !== req.params.id);
res.json({ message: `User ${req.params.id} ์ญ์ ์๋ฃ / Deletion complete` });
});
app.listen(PORT, () => console.log(`Server: http://localhost:${PORT}`));
๐๐ป ์คํฌ๋ฆฐ ์ท / ScreenShot
