๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • What would life be If we had no courage to attemp anything?
๐“๐จ๐๐š๐ฒ ๐ˆ ๐‹๐ž๐š๐ซ๐ง

[DX ๊ฐœ์„ ] Orval์„ ํ™œ์šฉํ•œ API Boilerplate ์ž๋™ํ™” ๊ฒฝํ—˜๊ธฐ

by DevIseo 2026. 5. 12.

๊ธฐํš์€ ๊ณ„์† ๋ฐ”๋€Œ๋Š”๋ฐ ๊ฐœ๋ฐœ ์ผ์ •์€ ๊ณ ์ •๋˜์–ด ์žˆ์—ˆ๋‹ค

์„œ๋น„์Šค ์ „์ฒด ๊ฐœํŽธ์„ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด์„œ ์งง์€ ๊ธฐ๊ฐ„ ์•ˆ์— ๋งค์šฐ ๋งŽ์€ ํ™”๋ฉด์„ ๊ฐœ๋ฐœํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํŽ˜์ด์ง€, ์Šฌ๋ผ์ด๋“œ์•„์›ƒ, ๋ชจ๋‹ฌ์„ ํฌํ•จํ•ด 30๊ฐœ ์ด์ƒ์˜ ํ™”๋ฉด์ด ์ƒˆ๋กญ๊ฒŒ ์ถ”๊ฐ€๋˜์–ด์•ผ ํ–ˆ๊ณ , ๋ฌธ์ œ๋Š” ๋‹จ์ˆœํžˆ ํ™”๋ฉด ์ˆ˜๋งŒ ๋งŽ์•˜๋˜ ๊ฒƒ์ด ์•„๋‹ˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ธฐํš์€ ์™„์ „ํžˆ ํ™•์ •๋˜์ง€ ์•Š์€ ์ƒํƒœ์˜€๊ณ , ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜๋Š” ๋™์•ˆ์—๋„ ๊ณ„์†ํ•ด์„œ ์š”๊ตฌ์‚ฌํ•ญ์ด ๋ณ€๊ฒฝ๋˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ๋ฆด๋ฆฌ์ฆˆ ์ผ์ •์€ ๊ณ ์ •๋˜์–ด ์žˆ์—ˆ๊ณ , ๊ฒฐ๊ตญ ๊ฐœ๋ฐœ์ž๊ฐ€ ์‹ค์ œ ๊ตฌํ˜„์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ๊ฐ„์€ ๊ณ„์† ์ค„์–ด๋“œ๋Š” ๊ตฌ์กฐ์˜€์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฐ ์ƒํ™ฉ์—์„œ ์ €๋Š” ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋‹ค์Œ ์งˆ๋ฌธ์„ ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

“์ง€๊ธˆ ๋‚ด๊ฐ€ ์ •๋ง ์ œํ’ˆ ๊ฐœ๋ฐœ์— ์‹œ๊ฐ„์„ ์“ฐ๊ณ  ์žˆ๋Š” ๊ฑธ๊นŒ? ์˜๋ฏธ ์—†๋Š” ๋ฐ˜๋ณต ์ž‘์—…์— ์‹œ๊ฐ„์„ ์Ÿ๋Š”๊ฑฐ ์•„๋‹๊นŒ?” 

 


๋ฐ˜๋ณต๋˜๋Š” API Boilerplate ๋ฌธ์ œ

๊ธฐ์กด ๊ตฌ์กฐ์—์„œ๋Š” ์ƒˆ๋กœ์šด API๊ฐ€ ์ถ”๊ฐ€๋  ๋•Œ๋งˆ๋‹ค ๋ฐ˜๋ณต์ ์œผ๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋งŽ์•˜์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

API ํ†ต์‹  ๊ณ„์ธต

import axios from '@/lib/axios';

export const fetchProducts = async (categoryId: string) => {
  try {
    const { data } = await axios.get(
      `/api/categories/${categoryId}/products`
    );

    return data;
  } catch (error) {
    console.error('Failed to fetch products', error);
    throw error;
  }
};

React Query ๊ณ„์ธต

import { useQuery } from '@tanstack/react-query';
import { fetchProducts } from './fetchProducts';

export const useProducts = (categoryId: string) => {
  return useQuery({
    queryKey: ['products', categoryId],
    queryFn: () => fetchProducts(categoryId),
    enabled: !!categoryId,
  });
};

๋‹น์‹œ ์ž‘์„ฑํ•˜๋˜ ๋Œ€๋ถ€๋ถ„์˜ API ์ฝ”๋“œ๋“ค์€ ๋‹ค์Œ ์š”์†Œ๋งŒ ๋‹ฌ๋ž์Šต๋‹ˆ๋‹ค.

  • endpoint
  • request/response type
  • queryKey
  • mutation/query ์—ฌ๋ถ€

ํ•˜์ง€๋งŒ ์ „์ฒด ๊ตฌ์กฐ๋Š” ๊ฑฐ์˜ ๋™์ผํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ ์ €๋Š” ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ๋ณด๋‹ค ๋ฐ˜๋ณต์ ์ธ boilerplate ์ƒ์‚ฐ์— ๋งŽ์€ ์‹œ๊ฐ„์„ ์“ฐ๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ธ์‹ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ‰์†Œ์—๋Š” ํฌ๊ฒŒ ์ฒด๊ฐ๋˜์ง€ ์•Š์•˜์ง€๋งŒ, ์„œ๋น„์Šค ์ „์ฒด ๊ฐœํŽธ์ฒ˜๋Ÿผ API ์—ฐ๋™์ด ํญ๋ฐœ์ ์œผ๋กœ ์ฆ๊ฐ€ํ•˜๋Š” ์‹œ์ ์—์„œ๋Š” ์ด ๋ฐ˜๋ณต ์ž‘์—…์ด ์ผ์ • ์ž์ฒด๋ฅผ ์œ„ํ˜‘ํ•˜๋Š” ์ˆ˜์ค€์˜ ๋น„์šฉ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


์ฒ˜์Œ์—๋Š” AI๋กœ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ํ–ˆ๋‹ค

์ฒ˜์Œ์—๋Š” Cursor, Claude ๊ฐ™์€ AI ๊ธฐ๋ฐ˜ ์ฝ”๋“œ ์ƒ์„ฑ ๋ฐฉ์‹์„ ๊ณ ๋ฏผํ–ˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด:

  • ํŒ€ ๋‚ด๋ถ€ ๊ทœ์น™ ์ •์˜
  • rules.md ์ž‘์„ฑ
  • API ์ƒ์„ฑ ๊ทœ์น™ ๋ฌธ์„œํ™”
  • ํ”„๋กฌํ”„ํŠธ ๊ธฐ๋ฐ˜ ์ƒ์„ฑ

๊ฐ™์€ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ณ ๋ฏผํ•˜๋‹ค ๋ณด๋‹ˆ ํ•œ ๊ฐ€์ง€ ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

“์ด ๋ฌธ์ œ๋ฅผ ์ •๋ง AI๋กœ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๊ฑธ๊นŒ?”

 

 

์ด๋ฏธ ์ œ ํŒ€์—๋Š” OpenAPI ๊ธฐ๋ฐ˜ Swagger ๋ช…์„ธ๊ฐ€ ์กด์žฌํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ ‡๋‹ค๋ฉด ์‚ฌ๋žŒ์ด ํ”„๋กฌํ”„ํŠธ๋ฅผ ํ†ตํ•ด ๋ฐ˜๋ณต ์ƒ์„ฑํ•˜๋„๋ก ๋งŒ๋“œ๋Š” ๊ฒƒ๋ณด๋‹ค, OpenAPI ์ŠคํŽ™ ์ž์ฒด๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๊ตฌ์กฐ์ ์ด์ง€ ์•Š์„๊นŒ ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๋ฐœ๊ฒฌํ•œ ๋„๊ตฌ๊ฐ€ ๋ฐ”๋กœ Orval์ด์—ˆ์Šต๋‹ˆ๋‹ค.


Orval์„ ์„ ํƒํ•œ ์ด์œ 

์šฐ๋ฆฌ ํŒ€์€ ๋ฐฑ์—”๋“œ๊ฐ€ ์ด๋ฏธ OpenAPI ๊ธฐ๋ฐ˜์œผ๋กœ API๋ฅผ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ์ƒˆ๋กœ์šด ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ฐ•์š”ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๋ช…์„ธ๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

Orval์€ OpenAPI ์ŠคํŽ™์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ค์Œ์„ ์ž๋™ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

  • axios ๊ธฐ๋ฐ˜ API ํ•จ์ˆ˜
  • react-query hook
  • TypeScript ํƒ€์ž…
  • MSW mock ๋ฐ์ดํ„ฐ

์ฆ‰, ๊ธฐ์กด์— ๋ฐ˜๋ณต์ ์œผ๋กœ ์ž‘์„ฑํ•˜๋˜ boilerplate ๋Œ€๋ถ€๋ถ„์„ ์ž๋™ํ™”ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.


ํ•˜์ง€๋งŒ ์ „์ฒด ์ ์šฉ์€ ํ•˜์ง€ ์•Š์•˜๋‹ค

์ค‘์š”ํ–ˆ๋˜ ๊ฑด “์–ด๋–ป๊ฒŒ ๋„์ž…ํ•  ๊ฒƒ์ธ๊ฐ€”์˜€์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ ์„œ๋น„์Šค์—๋Š” ๊ธฐ์กด API ๊ตฌ์กฐ๊ฐ€ ๋งค์šฐ ๋งŽ์ด ์กด์žฌํ•˜๊ณ  ์žˆ์—ˆ๊ณ , ์ „์ฒด๋ฅผ ํ•œ ๋ฒˆ์— ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ์˜ํ–ฅ๋„๊ฐ€ ๋„ˆ๋ฌด ์ปธ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋ž˜์„œ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž์™€ ๋…ผ์˜ ํ›„ ์‹ ๊ทœ๋กœ ์ถ”๊ฐ€๋˜๋Š” API์— ๋Œ€ํ•ด์„œ๋งŒ ์„ ๋ณ„์ ์œผ๋กœ ์ ์šฉ ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ฒฐ์ •์€ ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋งค์šฐ ์ค‘์š”ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

์™œ๋ƒํ•˜๋ฉด:

  • ๊ธฐ์กด ์ฝ”๋“œ ์˜ํ–ฅ ์ตœ์†Œํ™”
  • ์ ์ง„์  ๋„์ž… ๊ฐ€๋Šฅ
  • ํŒ€ ์ ์‘ ๋น„์šฉ ๊ฐ์†Œ
  • ๋ฆฌ์Šคํฌ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ

์ด๋ผ๋Š” ์žฅ์ ์ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์‹ค๋ฌด์—์„œ๋Š” “์ข‹์€ ๊ธฐ์ˆ ”๋ณด๋‹ค “์•ˆ์ „ํ•˜๊ฒŒ ๋„์ž… ๊ฐ€๋Šฅํ•œ ๊ธฐ์ˆ ”์ด ๋” ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.


์‹ค์ œ ์ ์šฉ ๋ฐฉ์‹

์šฐ๋ฆฌ๋Š” tags-split ๋ชจ๋“œ๋ฅผ ํ™œ์šฉํ•ด OpenAPI tag ๊ธฐ์ค€์œผ๋กœ ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

export default defineConfig({
  ecommerceApi: {
    input: {
      target: 'http://localhost:8080/v3/api-docs',
    },
    output: {
      mode: 'tags-split',
      target: 'src/api/generated',
      client: 'react-query',
      mock: true,
    },
  },
});

 

 

config๋ฅผ ์„ค์ • ํ›„ ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

yarn generate:api

 

์œ„์˜ script ํ•œ ๋ฒˆ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๊ฐ€ ์ž๋™ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

src/api/generated/
โ”œโ”€โ”€ product/
โ”œโ”€โ”€ category/
โ”œโ”€โ”€ user/
โ”œโ”€โ”€ order/
โ””โ”€โ”€ ...

 

 

์‹ค์ œ๋กœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ๋“ค๊นŒ์ง€ ๋ชจ๋‘ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  • axios ํ•จ์ˆ˜
  • react-query hook
  • schema type
  • msw mock

 


๊ฒฐ๊ณผ — API ์—ฐ๋™ ์‹œ๊ฐ„์ด ๊ทน์ ์œผ๋กœ ๊ฐ์†Œํ–ˆ๋‹ค

๋„์ž… ์ดํ›„ ๊ฐ€์žฅ ํฌ๊ฒŒ ์ฒด๊ฐํ•œ ๊ฒƒ์€ “์ด์ œ API ์—ฐ๋™ ์ž์ฒด์— ์‹œ๊ฐ„์„ ๊ฑฐ์˜ ์“ฐ์ง€ ์•Š๊ฒŒ ๋˜์—ˆ๋‹ค”๋Š” ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

 

AS-IS

๊ธฐ์กด์—๋Š” ์ƒˆ๋กœ์šด API ํ•˜๋‚˜๊ฐ€ ์ถ”๊ฐ€๋  ๋•Œ๋งˆ๋‹ค ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์•ก์…˜์„ ๋ฐ˜๋ณตํ–ˆ์Šต๋‹ˆ๋‹ค.

  • axios ํ•จ์ˆ˜ ์ž‘์„ฑ
  • ํƒ€์ž… ์ •์˜
  • react-query hook ์ž‘์„ฑ
  • queryKey ๊ด€๋ฆฌ
  • mutation/query ๋ถ„๋ฆฌ

๋“ฑ์„ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

 

TO-BE

ํ•˜์ง€๋งŒ Orval ๋„์ž… ์ดํ›„์—๋Š” ๋‹ค์Œ ์•ก์…˜์œผ๋กœ ๋Œ€๋ถ€๋ถ„์ด ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  • OpenAPI ์ •์˜
  • generate ์‹คํ–‰

 

 

 

์‹ค์ œ๋กœ ์„œ๋น„์Šค ์ „์ฒด ๊ฐœํŽธ ๊ธฐ๊ฐ„ ๋™์•ˆ ๊ธฐ์กด ๋Œ€๋น„ API ์—ฐ๋™์— ์‚ฌ์šฉํ•˜๋˜ ์‹œ๊ฐ„์˜ 10%๋„ ์•ˆ ๋˜๋Š” ์ˆ˜์ค€์œผ๋กœ ๊ฐœ๋ฐœ ์‹œ๊ฐ„์„ ์ค„์ผ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ๋•๋ถ„์— ์•„๋ž˜์™€ ๊ฐ™์€ “์ œํ’ˆ ์ž์ฒด์˜ ๋ฌธ์ œ”์— ๋” ๋งŽ์€ ์‹œ๊ฐ„์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

  • ์ด‰๋ฐ•ํ•œ ์ผ์ • ๋Œ€์‘
  • ๊ธฐํš ๋ณ€๊ฒฝ ๋Œ€์‘
  • UI/UX ๊ฐœ์„  ์ง‘์ค‘

 


๊ทธ๋Ÿฐ๋ฐ ์ž๋™ํ™”์—๋„ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค

ํ•˜์ง€๋งŒ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” tags-split ๋ชจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— OpenAPI์˜ tag ์ด๋ฆ„ ๊ธฐ์ค€์œผ๋กœ generated ํŒŒ์ผ ๊ฒฝ๋กœ๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

import { useProducts } from '@/api/generated/product/product';

 

 

 

๋ฌธ์ œ๋Š” ๋ฐฑ์—”๋“œ์—์„œ tag ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•˜๋ฉด generated ๊ฒฝ๋กœ ์ž์ฒด๊ฐ€ ๋ฐ”๋€Œ์–ด๋ฒ„๋ฆฐ๋‹ค๋Š” ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์—์„œ import ๊ฒฝ๋กœ๊ฐ€ ๋Œ€๋Ÿ‰์œผ๋กœ ๊นจ์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

 

์ฆ‰, ์ž๋™ ์ƒ์„ฑ ์ฝ”๋“œ์™€ ์„œ๋น„์Šค ์ฝ”๋“œ๊ฐ€ ๋„ˆ๋ฌด ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ(coupling)๋˜์–ด ์žˆ์—ˆ๋˜ ๊ฒƒ์ž…๋‹ˆ๋‹ค.


ํ•ด๊ฒฐ — Generated Layer๋ฅผ ์ง์ ‘ ์ฐธ์กฐํ•˜์ง€ ์•Š๋„๋ก ๋งŒ๋“ค์—ˆ๋‹ค

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌ์กฐ๋ฅผ ๋‹ค์‹œ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ์•„์ด๋””์–ด๋Š” ์„œ๋น„์Šค ์ฝ”๋“œ๊ฐ€ generated ๊ตฌ์กฐ๋ฅผ ์ง์ ‘ ์•Œ์ง€ ๋ชปํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

์ €๋Š” ์ค‘๊ฐ„ layer๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

src/api/hooks/*

 

// product.ts
export * from '../generated/product/product';

 ์œ„์˜ ์˜ˆ์‹œ ์ฝ”๋“œ์ฒ˜๋Ÿผ barrel ํŒŒ์ผ๋งŒ ๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

๊ทธ๋ฆฌ๊ณ  ์„œ๋น„์Šค ์ฝ”๋“œ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์˜€์Šต๋‹ˆ๋‹ค.

import { useProducts } from '@/api/hooks/product';

 

 

 

 


์ด ๊ตฌ์กฐ๊ฐ€ ์ค‘์š”ํ–ˆ๋˜ ์ด์œ 

์ดํ›„๋ถ€ํ„ฐ๋Š” ๋ฐฑ์—”๋“œ์—์„œ tag ์ด๋ฆ„์ด ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„

  • generated ๊ฒฝ๋กœ๋งŒ ์ˆ˜์ •
  • barrel export๋งŒ ์ˆ˜์ •

ํ•˜๋ฉด ๋˜์—ˆ๊ณ , ์‹ค์ œ ์„œ๋น„์Šค ์ฝ”๋“œ ์ˆ˜์ •์€ ๊ฑฐ์˜ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

๊ฒฐ๊ตญ ์ด ๊ตฌ์กฐ๋Š”

  • generated layer
  • service layer

์‚ฌ์ด์— ์™„์ถฉ ์ง€์ ์„ ๋งŒ๋“  ์…ˆ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

์ž๋™ํ™” ์ž์ฒด๋ณด๋‹ค “์ž๋™ํ™” ๊ฒฐ๊ณผ๋ฌผ์„ ์–ด๋–ป๊ฒŒ ๊ฒฉ๋ฆฌํ•  ๊ฒƒ์ธ๊ฐ€”๊ฐ€ ๋” ์ค‘์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ๊ฒฝํ—˜ํ•˜๊ฒŒ ๋œ ์ˆœ๊ฐ„์ด์—ˆ์Šต๋‹ˆ๋‹ค.

 

 


๋งˆ๋ฌด๋ฆฌ

์ด๋ฒˆ ๊ฒฝํ—˜์„ ํ†ตํ•ด ๋А๋‚€ ์ ์€ ๋‹จ์ˆœํžˆ “Orval์ด ํŽธํ•˜๋‹ค”๊ฐ€ ์•„๋‹ˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ •๋ง ์ค‘์š”ํ–ˆ๋˜ ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

  • ๋ฐ˜๋ณต ์ž‘์—… ์ œ๊ฑฐ
  • ๊ฐœ๋ฐœ์ž ์ง‘์ค‘๋„ ํ–ฅ์ƒ
  • ์ผ์ • ๋Œ€์‘ ๋Šฅ๋ ฅ ํ™•๋ณด
  • ๋ณ€๊ฒฝ ๋Œ€์‘ ๋น„์šฉ ๊ฐ์†Œ

 

ํŠนํžˆ ์„œ๋น„์Šค ์ „์ฒด ๊ฐœํŽธ์ฒ˜๋Ÿผ ์š”๊ตฌ์‚ฌํ•ญ์ด ๊ณ„์† ๋ฐ”๋€Œ๊ณ , API๊ฐ€ ๊ธ‰์ฆํ•˜๋ฉฐ ์ผ์ •์€ ๊ณ ์ •๋œ ์ƒํ™ฉ์—์„œ๋Š” DX ๊ฐœ์„ ์ด ๋‹จ์ˆœํ•œ ํŽธ์˜์„ฑ์ด ์•„๋‹ˆ๋ผ ์ƒ์‚ฐ์„ฑ๊ณผ ์ผ์ • ์•ˆ์ •์„ฑ์„ ์ง์ ‘์ ์œผ๋กœ ์ขŒ์šฐํ•œ๋‹ค๊ณ  ๋А๊ผˆ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ๋˜ ํ•˜๋‚˜ ๋А๋‚€ ์ ์€ ์ž๋™ํ™”๋Š” ์ƒ์„ฑ ์ž์ฒด๋ณด๋‹ค coupling ๊ด€๋ฆฌ๊ฐ€ ๋” ์ค‘์š”ํ•˜๋‹ค๋Š” ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

 

๋ฐ˜๋ณต ์ž‘์—…์„ ์ค„์ด๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ๋๋‚˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ,
๊ทธ ์ž๋™ํ™” ๊ฒฐ๊ณผ๋ฌผ์ด ์„œ๋น„์Šค ๊ตฌ์กฐ๋ฅผ ์นจ๋ฒ”ํ•˜์ง€ ์•Š๋„๋ก ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ๊นŒ์ง€ ํฌํ•จ๋˜์–ด์•ผ ์ง„์งœ DX ๊ฐœ์„ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋Œ“๊ธ€