ํฐ์คํ ๋ฆฌ ๋ทฐ
์ง๋ ๊ฐ์ธ ๊ณผ์ ๋ถํฐ ๋๋ฌด ํท๊ฐ๋ฆฌ๋ ๋ผ์ฐํธ ํธ๋ค๋ฌ, ์๋ฒ ์ก์
[๊ธฐ์กด ์ง์]
๋ผ์ฐํธ ํธ๋ค๋ฌ๋ ์ฃผ๋ก ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ๋ฉฐ GET, POST ๋ฑ์ ์ด์ฉํด์ ์๋ฒ๋ก ์์ฒญ์ ๋ณด๋ด๊ณ ,
๋์ ๋ก์ปฌํธ์คํธ ์๋ฒ๋ก ์๋ต์ ์ค๋ค.
์๋ฒ ์ก์
์ ์ฃผ๋ก ์๋ฒ ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ๋ฉฐ ๋น๋๊ธฐ ํจ์๋ฅผ ํตํด ์์ฒญํ๊ณ ์๋ต์ ๋ฐ๋๋ค.
์ ๋๋ก ์๊ณ ์์๋ค.
๋์ ์ฐจ์ด์ ์ ์๋ต์ ์ฌ์ฉํ๋ ๋ถ๋ถ์ ์๋ค๊ณ ์๊ฐํ๋ค.
- ๋ผ์ฐํธ ํธ๋ค๋ฌ : ํธ๋ค๋ฌ -> ๋ด ์๋ฒ ํจ์ -> ์ค์ ์ฌ์ฉ
- ์๋ฒ ์ก์ : ํจ์ -> ์ค์ ์ฌ์ฉ
๋์ ํน์ง์ ํ์คํ ๋น๊ตํด๋ณด๊ณ ์ ํ๋ค.
Route Handler
// app/api/hello/route.ts
import { NextResponse } from "next/server";
// 1. GET ์์ฒญ์ ์ฒ๋ฆฌํ๋ ํธ๋ค๋ฌ
export async function GET() {
return NextResponse.json({ message: "Hello, Next.js API!" });
}
// 2. POST ์์ฒญ์ ์ฒ๋ฆฌํ๋ ํธ๋ค๋ฌ
export async function POST(request: Request) {
const data = await request.json();
return NextResponse.json({ received: data });
}
// 3. ๋กํ
์ด์
API ๋ผ์ฐํธ ํธ๋ค๋ฌ + ํํฐ
export const GET = async (): Promise<NextResponse> => {
const res = await fetch(ROTATION_API_URL, {
headers: {
"X-Riot-Token": process.env.RIOT_API_KEY!,
},
};
const data = await res.json();
return NextResponse.json();
};
๐HTTP ์์ฒญ / ์๋ต์ผ๋ก ๋์ํ๋ API ์๋ํฌ์ธํธ ๊ตฌํ
GET, POST, PATCH, DELETE ๋ฑ์ HTTP ์์ฒญ ๋ฉ์๋ ๋ณ๋ก ํธ๋ค๋ฌ๋ฅผ ์์ฑํ๋ค.
๊ทธ๋ฅผ ํตํด ๋ผ์ฐํฐ ๊ตฌ์กฐ์ ๊ธฐ๋ฐํ API ์๋ํฌ์ธํธ๊ฐ ์์ฑ๋๋ค.
์ฆ, ํ์ผ ๊ตฌ์กฐ๊ฐ app/api/rotation/route.ts ๋ผ๋ฉด
API ์๋ํฌ์ธํธ๋ 'api/rotation' ์ด ๋๋ ๊ฒ์ด๋ค.
๐์๋ฒ์ ํด๋ผ์ด์ธํธ์ ๋ช ํํ ํต์ ๊ตฌ์กฐ
์๋ฒ์ ์์ฒญํ ๊ฐ์ด ๋์ ๋ผ์ฐํฐ ๊ตฌ์กฐ์ ๋ฐ๋ผ ์๋ํฌ์ธํธ๋ก ์์ฑ๋๊ธฐ ๋๋ฌธ์
์๋ฒ <-> ํด๋ผ์ด์ธํธ๋ก ์์ฒญ ๋ฐ ์๋ต ๊ตฌ์กฐ๊ฐ ํ์คํ๋ค
๐๋ฐ์ดํฐ ์๋ต ๊ฐ์ด ์๋ฒ -> ๋ธ๋ผ์ฐ์ ์ ์ ๋ฌ๋๊ธฐ ๋๋ฌธ์ ๋ฏผ๊ฐํ ์ ๋ณด ์ฃผ์!
Api Key ๊ฐ์ ๊ฒฝ์ฐ๋ ํ๊ฒฝ ๋ณ์๋ก ์ค์ ํ๊ฑฐ๋
Authorization, x-api-key ๊ฐ์ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ์๋ฒ ์๋ต ํค๋์ ํฌํจํ์ง ์๋๋ก ์ฒ๋ฆฌ.
๐App route ๋ฐฉ์์์ ์ฌ์ฉํ๋ฉฐ ํด๋ผ์ด์ธํธ์์ fetch ์์ฒญ์ ๋ณด๋ผ ๋๋ง ์คํ
๋ผ์ฐํฐ ๊ตฌ์กฐ์ ๋ฐ๋ผ ์๋ํฌ์ธํธ๊ฐ ์์ฑ๋๊ธฐ ๋๋ฌธ์ ์ฑ ๋ผ์ฐํธ์์ ์ฌ์ฉํ๋ค.
ํ์ด์ง ๋ผ์ฐํฐ์์๋ API Routes (pages/api/*.ts) ๋ฐฉ์์ ์ฌ์ฉํด์ผ ํ๋ค.
์์ฑ๋ API ์๋ํฌ์ธํธ๋ฅผ ํ์น ํจ์๋ก ์์ฒญํ๋ ๋ก์ง์ด ์์ด์ผ์ง ๋ผ์ฐํธ ํธ๋ค๋ฌ๊ฐ ์คํ๋๋ค.
// ๋กํ
์ด์
๋ผ์ฐํธ ํธ๋ค๋ฌ ์๋ต
export const getChampionRotation = async (): Promise<Champions[]> => {
const res = await fetch("/api/rotation");
const data = await res.json();
return data;
};
Server Action
// ์ฑํผ์ธ ๋ชฉ๋ก ํจ์นญ
export async function fetchChampionList(): Promise<Champions[]> {
const chamUrl = await CHAMPION_LIST_URL();
const res = await fetch(chamUrl, { next: { revalidate: 86400 } });
const { data } = await res.json();
//ํด๋น ํ์ด์ง๋ก ์๋ฌ ๋ณด๋ด๊ธฐ
if (!res.ok) {
throw new Error("์ฑํผ์ธ ๋ชฉ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋ ์ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค!");
}
return Object.values(data);
}
๐"use server" + ๋น๋๊ธฐ ํจ์
ํ์ผ ์ต์๋จ์ "use server" ๋ฅผ ๋ช ์ํด์ฃผ์ด์ผ Next๊ฐ ํด๋น ๋ก์ง๋ค์ ์๋ฒ์์ ์ฌ์ฉํ๋ค๊ณ ์ธ์ํ๋ค.
async - await ๋ฅผ ์ฌ์ฉํ๋ ๋น๋๊ธฐ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๋ค.
์ด๋ ๊ผญ fetch๋ฅผ ์ฐ์ง ์์๋ ๋๋ฉฐ DB ์ ๊ทผ, ํ์ผ ์ฒ๋ฆฌ ๋ฑ์ ์์ ๋กญ๊ฒ ํ ์ ์๋ค.
๐ํด๋ผ์ด์ธํธ์์ ์ง์ ์๋ฒ ์ ์ฉ ํจ์ ํธ์ถ ๊ฐ๋ฅ
์๋ฒ ์ก์ ์ ์๋ฒ์์ ์ฌ์ฉ๋๋ ํจ์์ด์ง๋ง ํด๋ผ์ด์ธํธ์์๋ ์ง์ ํธ์ถ์ด ๊ฐ๋ฅํ๋ค.
์ง์ ํธ์ถํ์ฌ ๊ทธ ์๋ต๊ฐ์ ๋ฐ์๋ณผ ์ ์๋ค.
๐๋ณ๋์ API ๋ผ์ฐํฐ๊ฐ ํ์ ์์
๋ณดํต API ์์ฒญ์ ํ ๋๋ 'pages/api/my-action.js'์ฒ๋ผ API ๋ผ์ฐํฐ ํ์ผ์ ๋ง๋ค์ด์ผ ํด๋ผ์ด์ธํธ์์ ํด๋น API๋ฅผ ํธ์ถํ ์ ์์๋ค.
ํ์ง๋ง ์๋ฒ ์ก์ ์ ๋ผ์ฐํฐ ์์ด ํด๋ผ์ด์ธํธ์์ ๋ฐ๋ก ํธ์ถ์ด ๊ฐ๋ฅํ๋ค.
์๋ฒ ์ก์ ์ ์๋ฒ์์ ์ง์ ์คํ๋๊ณ ์์ฒด์ ์ผ๋ก ๋คํธ์ํฌ ์์ฒญ์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ด๋ค.
๐ํจ์ ํธ์ถ ํ์
์ ์์์์์ฒ๋ผ fetchChampionList ํจ์๋ฅผ ๋ง๋ค๊ณ ,
์ฌ์ฉํ๋ ๊ณณ์์๋ const data = await fetchChampionList(); ๋ก ์๋ฒ ์ก์ ํจ์๋ฅผ ํธ์ถํ์ฌ ์๋ต ๊ฐ์ ๋ฐ๋๋ค.
๐๋ณด์ ๊ฐํ
์๋ฒ ์ก์ ์ ์๋ฒ <-> ์๋ฒ์ ํต์ ์ด๊ธฐ ๋๋ฌธ์ ์๋ต ๊ฐ์ด ๋ธ๋ผ์ฐ์ ์ ์ค์ง ์๋๋ค.
๋ฐ๋ผ์ ๋ฏผ๊ฐํ ์ ๋ณด ๋ฑ์ ๋ ธ์ถ์ํค์ง ์๊ณ ํต์ ์ด ๊ฐ๋ฅํ๋ค.
๐ํด๋ผ์ด์ธํธ์์ ์ฌ์ฉ ์, POST ์์ฒญ
๋ณดํต POST ์์ฒญ์ body์ ๊ฐ์ ๋ด์ ์๋ก์ด ๊ฐ์ ์ถ๊ฐํ๋ ์ญํ ์ด๋ค.
ํ์ง๋ง ์๋ฒ ์ก์ ์์๋ ์ด๋ค ์์ ์ ์๋ฒ์์ ์ฒ๋ฆฌํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ ์ญํ ์ด๋ค.
์ด ์์ฒญ์ ํต์ฌ์ ์๋ฒ์์ ํน์ ๋ก์ง์ ์คํํ๋ ๊ฒ์ด๋ค.
1. ์๋ฒ ์ก์ ์์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
"use server";
export async function processData(data: string) {
// ์๋ฒ์์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
console.log("์๋ฒ์์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ:", data);
const processedData = data.toUpperCase(); // ์: ๋๋ฌธ์๋ก ๋ณํ
return processedData;
}
2. ์ธ๋ถ API ํธ์ถ
"use server";
export async function fetchWeather(city: string) {
const res = await fetch(`https://api.weather.com/v1/${city}`);
const data = await res.json();
return data;
}
๐์๋ฒ ์ก์ ํจ์์ ์ธ์๊ฐ ์์ฒญ body์ ๋ด๊น
์ธ์์ ์๋ฌด ๊ฐ๋ ๋ด๊ธฐ์ง ์๋๋ค๋ฉด ์์ฒญ์ ๋ฐ๋ฅธ ์๋ต๊ฐ์ ๋ฐ์์ค๋ ๊ฒ์ด๋ค.
ํ์ง๋ง ์ธ์์ ์ด๋ค ๊ฐ์ด ๋ด๊ธด ๊ฒฝ์ฐ, ๊ทธ ๊ฐ์ด body์ ๋ด๊ฒจ์ ์์ฒญ์ด ๋๋ค. (๊ฐ๋ฐ์๋๊ตฌ > ๋คํธ์ํฌ ํญ์์ ํ์ธ)
1. ์๋ฒ ์ก์ ํจ์์ ์ ๋ฌ๋ ์ธ์ ํ์ฉ
- ์ธ์์ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ค์ํ ๊ณ์ฐ, ๋ก์ง ์คํ ๊ฐ๋ฅ
"use server";
export async function processData(data: string, count: number) {
// ํด๋ผ์ด์ธํธ์์ ๋ฐ์ ๋ฐ์ดํฐ์ count๋ฅผ ์ด์ฉํ ์์
console.log("๋ฐ์ ๋ฐ์ดํฐ:", data);
console.log("๋ฐ์ ์ซ์:", count);
return `${data}์ ๊ธธ์ด๋ ${data.length}์ด๊ณ , ์ซ์ ${count}๋ ${count * 2}์
๋๋ค.`;
}
2. ์๋ฒ ์ก์ ํจ์ ํธ์ถ (ํด๋ผ์ด์ธํธ)
- ํด๋ผ์ด์ธํธ์์ ์๋ฒ ์ก์ ์ ํ์ฉํ ๋ ์ธ์ ๊ฐ์ ๋๊ฒจ์ค
- ์๋ฒ์์ ์ด ๊ฐ์ ์ฒ๋ฆฌํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํด๋ผ์ด์ธํธ์ ๋ฐํ
"use client";
import { processData } from "./actions";
export default function MyComponent() {
const handleClick = async () => {
const data = "Hello, World!";
const count = 5;
const result = await processData(data, count);
console.log(result); // ์๋ฒ์์ ์ฒ๋ฆฌ๋ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅ
};
return <button onClick={handleClick}>์๋ฒ ์ก์
์คํ</button>;
}
3. ์ธ์๋ฅผ ์ด์ฉํ ๋ค์ํ ์คํ
- ์กฐ๊ฑด๋ฌธ์ ์ฌ์ฉํ์ฌ ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ์ ์ธ์ ํ์ฉ
- ์ธ๋ถ API ํธ์ถ์ ์ธ์ ์ ๋ฌ
4. ์ธ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋์ ์ธ ์คํ
- actionType์ ๋ฐ๋ผ ์๋ฒ์์ ๋ค๋ฅธ ์์ ์งํ
"use server";
export async function handleAction(actionType: string, data: any) {
if (actionType === "uppercase") {
return data.toUpperCase();
} else if (actionType === "reverse") {
return data.split('').reverse().join('');
} else {
return "์ ์ ์๋ ์์
";
}
}
๋ ์ค ์ด๋ ๊ฒ์ด ์ข๊ณ ๋์จ์ ๋ฐ์ง๋ ๊ฒ์ด ์๋ ๊ฐ์์ ํน์ฑ๊ณผ ์ญํ ์ด ์์ผ๋ฉฐ
์ํฉ์ ์ ํ์ ํ์ฌ ๊ทธ์ ๋ง๋ ๋ฐฉ์์ ์ ํํ๋ ๊ฒ์ด ์ค์ํ๋ค๊ณ ์๊ฐํ๋ค.
'Language > Next' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [์ฌ๋๋ณ] Next.js ์๋ฌ ํธ๋ค๋ง (error.tsx) (5) | 2025.04.26 |
|---|---|
| [/\/] Tanstack Query + Zustand ์ ์ญ ์ํ ๊ด๋ฆฌํ๊ธฐ (0) | 2025.03.21 |
| [/\/] Next.js์์ ๋งํ๋ '์๋ฒ'๋? (0) | 2025.03.19 |
| [/\/] Error Handling (0) | 2025.03.19 |
| [/\/] Next์ Tanstack Query (0) | 2025.03.19 |