Node.js의 HTTP 모듈을 이용해서 TODO앱을 만드는 법.
http 모듈을 import 한다.
const http = require("http");
createServer를 통해 서버를 만들 수 있다.
const server = http.createServer()
만든 서버는 server.listen(포트번호)를 통해 실행시킬 수 있다.
server.listen(8080, () => console.log("8080 포트 작동"));
createServer의 인자로 requestListener라는 콜백 함수를 넘길 수 있다. 해당 함수는 첫번째 인자로 request를, 두번째 인자로 response를 받는다.
res.setHeader(키, 밸류)를 통해 헤더값을 추가할 수 있으며,
res.write(chunk)를 통해 응답의 body값을 추가할 수 있다.
res.end(chunk?)는 요청에 대한 응답을 종료시키며, 종료와 함께 추가적인 body값을 보낼 수 있다.
const server = http.createServer((res, req)=> { res.setHeader("Content-Type", "application/json"); res.end("응답입니다."); })
헤더에 아래와 같이 추가하여 CORS 문제를 해결할 수 있다.
const server = http.createServer((req, res) => {
console.log(req.url);
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Content-Type"); //post 요청 등에서 Content-Type인 경우에도 CORS를 허용한다.
res.setHeader("Access-Control-Allow-Methods", "*"); //OPTIONS, GET, POST 이외의 요청에 대해서 허용
})
임시로 주고 받을 userInfo 데이터를 넣는다.
const http = require("http");
const userInfo = [
{
id: 1,
username: "john_doe",
email: "john@example.com",
},
];
userInfo를 가져와서 조회 및 생성을 하는 API이다.
이때 if 문으로 라우팅을 하고, 필요에 따라 return을 넣어주어야 한다.
아래에서는 req가 POST인 경우에 대해서도 return을 넣어주었다.
const server = http.createServer((req, res) => {
console.log(req.url);
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Content-Type"); //post 요청 등에서 Content-Type인 경우에도 CORS를 허용한다.
res.setHeader("Access-Control-Allow-Methods", "*"); //OPTIONS, GET, POST 이외의 요청에 대해서 허용
// application/json 타입으로 헤더에 콘텐츠 타입을 설정한다.
res.setHeader("Content-Type", "application/json");
if (req.url === "/") {
res.write(JSON.stringify({ url: "암것두 없다" }));
}
if (req.url.startsWith("/user")) {
if (req.method === "GET") {
res.write(JSON.stringify(userInfo));
}
if (req.method === "POST") {
let requestBody = "";
req
.on("data", (chunk) => {
requestBody += chunk;
})
.on("end", () => {
const user = JSON.parse(requestBody);
userInfo.push({ id: userInfo.at(-1).id + 1, ...user });
//아래의 두 코드는 같다.
res.end(JSON.stringify(userInfo));
// res.write(JSON.stringify(userInfo));
// res.end();
});
return; // return을 넣어주어야 res.end()가 작동하지 않는다. return하지 않으면 res.end가 한번 더 실행되며 잘못된 응답을 보내게 된다.
}
}
res.end();
});
/user는 리스트를 조회하고,
/user/:id는 특정 하나를 조회하도록 추가해보자.
const server = http.createServer((req, res) => {
console.log(req.url);
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Content-Type"); //post 요청 등에서 Content-Type인 경우에도 CORS를 허용한다.
res.setHeader("Access-Control-Allow-Methods", "*"); //OPTIONS, GET, POST 이외의 요청에 대해서 허용
// application/json 타입으로 헤더에 콘텐츠 타입을 설정한다.
res.setHeader("Content-Type", "application/json");
if (req.url === "/") {
res.write(JSON.stringify({ url: "암것두 없다" }));
}
if (req.url.startsWith("/user")) {
//url.split("/")[2]는 params를 의미한다.
if (!req.url.split("/")[2]) {
if (req.method === "GET") {
res.write(JSON.stringify(userInfo));
}
if (req.method === "POST") {
let requestBody = "";
req
.on("data", (chunk) => {
requestBody += chunk;
})
.on("end", () => {
const user = JSON.parse(requestBody);
userInfo.push({ id: userInfo.at(-1).id + 1, ...user });
res.end(JSON.stringify(userInfo));
});
return;
}
} else {
const userId = Number(req.url.split("/")[2]);
const userData = userInfo[userInfo.findIndex((e) => e.id === userId)];
if (req.method === "GET") {
res.write(JSON.stringify(userData));
}
// POST 요청을 활용한다.
if (req.method === "PATCH") {
let requestBody = "";
req
.on("data", (chunk) => {
requestBody += chunk;
})
.on("end", () => {
const user = JSON.parse(requestBody);
// 유저 객체의 키, 밸류를 수정하는 방식으로 업데이트를 실행한다.
// (객체 불변성을 지키지 않고 있음에 유의!)
Object.entries(user).forEach((entry) => {
const [key, value] = entry;
userData[key] = value;
});
res.end(JSON.stringify(userData));
});
return;
}
}
}
res.end();
});
server.listen(8080, () => console.log("8080 포트 작동"));
프론트엔드에서 fetch API를 통해서 응답을 주고 받은 방법은 아래와 같다.
fetch(요청).then(res=> res.json()).then(data=>{}) 와 같이 res를 json으로 파싱해주어야 한다. RESPONSE.json()은 비동기적으로 작동하며, PROMISE를 반환한다는 점에 유의하자.
import { useState } from "react";
import "./App.css";
function App() {
const [data, setData] = useState("");
const onClickHandler = () => {
fetch("http://localhost:8080", { method: "GET" })
.then((res) => {
//fetch의 결과물을 자바스크립트 객체로 반환한다..
return res.json();
})
.then((res) => {
//반환된 객체를 res에 저장한다.
setData(res);
})
.catch((e) => console.log(e));
};
const onGetUser = () => {
fetch("http://localhost:8080/user", { method: "GET" })
.then((res) => {
//fetch의 결과물을 자바스크립트 객체로 반환한다..
return res.json();
})
.then((res) => {
//반환된 객체를 res에 저장한다.
setData(res);
})
.catch((e) => console.log(e));
};
const onPostUser = () => {
const newDate = new Date();
fetch("http://localhost:8080/user", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: `john_doe${newDate.getSeconds()}`,
email: `john${newDate.getSeconds()}@example.com`,
}),
})
.then((res) => {
return res.json();
})
.then((res) => {
setData(res);
})
.catch((e) => console.log(e));
};
const onUpdateUser = () => {
const newDate = new Date();
fetch("http://localhost:8080/user/1", {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: `john_${newDate.getSeconds()}`,
}),
})
.then((res) => {
return res.json();
})
.then((res) => {
setData(res);
})
.catch((e) => console.log(e));
};
const onRetriveUser = () => {
fetch("http://localhost:8080/user/1", {
method: "GET",
})
.then((res) => {
return res.json();
})
.then((res) => {
setData(res);
})
.catch((e) => console.log(e));
};
return (
<>
<button onClick={onClickHandler}>버튼</button>
<button onClick={onGetUser}>user-get버튼</button>
<button onClick={onPostUser}>user-post버튼</button>
<button onClick={onUpdateUser}>user-1-patch버튼</button>
<button onClick={onRetriveUser}>user-1-get버튼</button>
<div>{JSON.stringify(data)}</div>
</>
);
}
export default App;