API 라우트란 특수한 형태의 URL으로 Next.js 어플리케이션에 추가하여 일반적인 브라우저 요청을 받고 사전 렌더링된 HTML 페이지를 돌려보내는 게 아니라 데이터를 수집하고, 사용하고 데이터베이스에 저장한 뒤 원하는 형태의 데이터를 돌려보내는 역할을 한다.
API 라우트는 URL 상에 직접 입력할 필요는 없지만 대신 JavaScript 코드인 Ajax 요청으로 트리거되므로 개발자는 해당 특정 코드를 페이지에 추가하여 백엔드에서 요청을 전송하게끔 하여 API가 데이터를 저장하거나 불러오도록 구성할 수 있다.
// pages/api/feedback.js
export default function handler(req, res) {
res.status(200).json({ message: "This works" }); // 받은 요청에 포함된 JSON 데이터를 반환
}
"http://localhost:3000/api/feedback"으로 요청을 전송하면 다음의 결과가 나온다. →
{"message":"This works"}
// pages/index.js
import { useRef } from "react";
function HomePage() {
const emailInputRef = useRef();
const feedbackInputRef = useRef();
function submitFormHandler(event) {
event.preventDefault();
const enteredEmail = emailInputRef.current.value;
const enteredFeedback = feedbackInputRef.current.value;
}
return (
<div>
<h1>The Home Page</h1>
<form onSubmit={submitFormHandler}>
<div>
<label htmlFor="email">Your Email</label>
<input type="email" id="email" ref={emailInputRef} />
</div>
<div>
<label htmlFor="feedback">Your Feedback</label>
<textarea id="feedback" rows="5" ref={feedbackInputRef} />
</div>
<button>Feedback</button>
</form>
</div>
);
}
export default HomePage;
// pages/api/feedback.js
import fs from "fs";
import path from "path";
export default function handler(req, res) {
if (req.method === "POST") {
const email = req.body.email;
const feedbackText = req.body.text;
const newFeedback = {
id: new Date().toISOString(),
email: email,
text: feedbackText,
};
// store that in a db or in a file
const filePath = path.join(process.cwd(), "data", "feedback.json");
const fileData = fs.readFileSync(filePath);
const data = JSON.parse(fileData);
data.push(newFeedback);
fs.writeFileSync(filePath, JSON.stringify(data));
res.status(201).json({ message: "Success", feedback: newFeedback });
} else {
res.status(200).json({ message: "This works" }); // 받은 요청에 포함된 JSON 데이터를 반환
}
}
// pages/index.js
import { useRef } from "react";
function HomePage() {
const emailInputRef = useRef();
const feedbackInputRef = useRef();
function submitFormHandler(event) {
event.preventDefault();
const enteredEmail = emailInputRef.current.value;
const enteredFeedback = feedbackInputRef.current.value;
const reqBody = { email: enteredEmail, text: enteredFeedback };
fetch("/api/feedback", {
method: "POST",
body: JSON.stringify(reqBody),
headers: {
"Content-Type": "application/json",
},
})
.then((res) => res.json())
.then((data) => console.log(data));
}
return (
<div>
<h1>The Home Page</h1>
<form onSubmit={submitFormHandler}>
<div>
<label htmlFor="email">Your Email</label>
<input type="email" id="email" ref={emailInputRef} />
</div>
<div>
<label htmlFor="feedback">Your Feedback</label>
<textarea id="feedback" rows="5" ref={feedbackInputRef} />
</div>
<button>Feedback</button>
</form>
</div>
);
}
export default HomePage;
// {message: 'Success', feedback: {…}}
// data/feedback.json
[
{
"id": "2024-04-01T09:32:22.649Z",
"email": "admin@admin.com",
"text": "admin data"
},
{
"id": "2024-04-01T09:33:29.198Z",
"email": "test@test.com",
"text": "test data"
}
]
import fs from "fs";
import path from "path";
function buildFeedbackPath() {
return path.join(process.cwd(), "data", "feedback.json");
}
function extractFeedback(filePath) {
const fileData = fs.readFileSync(filePath);
const data = JSON.parse(fileData);
return data;
}
export default function handler(req, res) {
if (req.method === "POST") {
const email = req.body.email;
const feedbackText = req.body.text;
const newFeedback = {
id: new Date().toISOString(),
email: email,
text: feedbackText,
};
// store that in a db or in a file
const filePath = buildFeedbackPath();
const data = extractFeedback(filePath);
data.push(newFeedback);
fs.writeFileSync(filePath, JSON.stringify(data));
res.status(201).json({ message: "Success", feedback: newFeedback });
} else {
// GET method
const filePath = buildFeedbackPath();
const data = extractFeedback(filePath);
res.status(200).json({ feedback: data }); // 받은 요청에 포함된 JSON 데이터를 반환
}
}
import { useRef, useState } from "react";
function HomePage() {
const [feedbackItems, setFeedbackItems] = useState([]);
const emailInputRef = useRef();
const feedbackInputRef = useRef();
function submitFormHandler(event) {
event.preventDefault();
const enteredEmail = emailInputRef.current.value;
const enteredFeedback = feedbackInputRef.current.value;
const reqBody = { email: enteredEmail, text: enteredFeedback };
fetch("/api/feedback", {
method: "POST",
body: JSON.stringify(reqBody),
headers: {
"Content-Type": "application/json",
},
})
.then((res) => res.json())
.then((data) => console.log(data));
}
function loadFeedbackHandler() {
fetch("/api/feedback")
.then((res) => res.json())
.then((data) => {
setFeedbackItems(data.feedback);
});
}
return (
<div>
<h1>The Home Page</h1>
<form onSubmit={submitFormHandler}>
<div>
<label htmlFor="email">Your Email</label>
<input type="email" id="email" ref={emailInputRef} />
</div>
<div>
<label htmlFor="feedback">Your Feedback</label>
<textarea id="feedback" rows="5" ref={feedbackInputRef} />
</div>
<button>Feedback</button>
</form>
<hr />
<button onClick={loadFeedbackHandler}>Load Feedback</button>
<ul>
{feedbackItems.map((item) => (
<li key={item.id}>{item.text}</li>
))}
</ul>
</div>
);
}
export default HomePage;
loadFeedbackHandler
함수가 동작하여 unordered list에 표현되도록 하였다.getStaticProps
를 이용해 데이터를 받아올 것이다.// pages/api/feedback.js
import fs from "fs";
import path from "path";
export function buildFeedbackPath() {
return path.join(process.cwd(), "data", "feedback.json");
}
export function extractFeedback(filePath) {
const fileData = fs.readFileSync(filePath);
const data = JSON.parse(fileData);
return data;
}
export
한다.//pages/feedback/index.js
import { buildFeedbackPath, extractFeedback } from "../api/feedback.js";
export default function FeedbackPage({ feedbackItems }) {
return (
<ul>
{feedbackItems.map((item) => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
}
export async function getStaticProps() {
const filePath = buildFeedbackPath();
const data = extractFeedback(filePath);
return {
props: {
feedbackItems: data,
},
};
}
export
한 두 함수를 불러와 getStaticProps
에서 실행. props.feedbackItems
로 리턴하여 표현하였다.// pages/api/[feedbackId].js
import { buildFeedbackPath, extractFeedback } from "./feedback.js";
export default function handler(req, res) {
if (req.method === "DELETE") {
//
}
const feedbackId = req.query.feedbackId;
const filePath = buildFeedbackPath();
const feedbackData = extractFeedback(filePath);
const selectedFeedback = feedbackData.find(
(feedback) => feedback.id === feedbackId
);
res.status(200).json({ feedback: selectedFeedback });
}
// pages/feedback/index.js
import { buildFeedbackPath, extractFeedback } from "../api/feedback.js";
import { useState } from "react";
export default function FeedbackPage({ feedbackItems }) {
const [feedbackData, setFeedbackData] = useState();
function loadFeedbackHandler(feedbackId) {
fetch(`/api/${feedbackId}`)
.then((response) => response.json())
.then((data) => {
setFeedbackData(data.feedback);
});
}
return (
<>
{feedbackData && <p>{feedbackData.email}</p>}
<ul>
{feedbackItems.map((item) => (
<li key={item.id}>
{item.text}{" "}
<button onClick={loadFeedbackHandler.bind(null, item.id)}>
Show Details...
</button>
</li>
))}
</ul>
</>
);
}
export async function getStaticProps() {
const filePath = buildFeedbackPath();
const data = extractFeedback(filePath);
return {
props: {
feedbackItems: data,
},
};
}
loadFeedbackHandler
와 상태를 추가하여 만약 feedbackData가 존재한다면 해당 데이터의 이메일을 출력하고자 한다.loadFeedbackHandler
는 버튼이 클릭되었을 때 동작하고, 해당 함수에 feedback의 id를 전달해야하므로 bind(null,item.id)
를 이용하여 id를 전달한다.