ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

Language/Next

[/\/] Route Handler, Server-Action

์ฑ„._. 2025. 3. 22. 02:05

์ง€๋‚œ ๊ฐœ์ธ ๊ณผ์ œ๋ถ€ํ„ฐ ๋„ˆ๋ฌด ํ—ท๊ฐˆ๋ฆฌ๋Š” ๋ผ์šฐํŠธ ํ•ธ๋“ค๋Ÿฌ, ์„œ๋ฒ„ ์•ก์…˜

๋”๋ณด๊ธฐ

[๊ธฐ์กด ์ง€์‹]

๋ผ์šฐํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ์ฃผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋ฉฐ 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 "์•Œ ์ˆ˜ ์—†๋Š” ์ž‘์—…";
  }
}

 

 

๋‘˜ ์ค‘ ์–ด๋А ๊ฒƒ์ด ์ข‹๊ณ  ๋‚˜์จ์„ ๋”ฐ์ง€๋Š” ๊ฒƒ์ด ์•„๋‹Œ ๊ฐ์ž์˜ ํŠน์„ฑ๊ณผ ์—ญํ• ์ด ์žˆ์œผ๋ฉฐ

์ƒํ™ฉ์„ ์ž˜ ํŒŒ์•…ํ•˜์—ฌ ๊ทธ์— ๋งž๋Š” ๋ฐฉ์‹์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
TAG
more
ยซ   2026/03   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
๊ธ€ ๋ณด๊ด€ํ•จ