Skip to main content
Sonamu๊ฐ€ ๋ฐฑ์—”๋“œ API๋กœ๋ถ€ํ„ฐ ํƒ€์ž… ์•ˆ์ „ํ•œ ํด๋ผ์ด์–ธํŠธ Service๋ฅผ ์ž๋™ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค.

์ž๋™ ์ƒ์„ฑ Service ๊ฐœ์š”

ํƒ€์ž… ์•ˆ์ „์„ฑ

๋ฐฑ์—”๋“œ์™€ ๋™๊ธฐํ™” ์ปดํŒŒ์ผ ํƒ€์ž„ ๊ฒ€์ฆ

Namespace ๊ธฐ๋ฐ˜

์ •์  ํ•จ์ˆ˜ ๊ฐ„๊ฒฐํ•œ ํ˜ธ์ถœ

TanStack Query

React Hook ์ž๋™ ์ƒ์„ฑ ์บ์‹ฑ๊ณผ ์žฌ๊ฒ€์ฆ

Subset ์ง€์›

ํ•„์š”ํ•œ ํ•„๋“œ๋งŒ ์„ฑ๋Šฅ ์ตœ์ ํ™”

์™œ ์ž๋™ ์ƒ์„ฑ์ธ๊ฐ€?

๋ฌธ์ œ: ์ˆ˜๋™ API ํด๋ผ์ด์–ธํŠธ์˜ ํ•œ๊ณ„

์ „ํ†ต์ ์ธ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์—์„œ๋Š” ๋ฐฑ์—”๋“œ API๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜๋™์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ˆ˜๋™ ํด๋ผ์ด์–ธํŠธ ์˜ˆ์‹œ:
์ด ๋ฐฉ์‹์˜ ๋ฌธ์ œ์ :
  1. ํƒ€์ž… ์•ˆ์ „์„ฑ ๋ถ€์žฌ: any ํƒ€์ž… ๋‚จ๋ฐœ, ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ ๋ฐœ์ƒ
  2. ๋ฐฑ์—”๋“œ ๋ณ€๊ฒฝ ์ถ”์  ๋ถˆ๊ฐ€: API๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด๋„ ํ”„๋ก ํŠธ์—”๋“œ๋Š” ๋ชจ๋ฆ„
  3. ์ค‘๋ณต ์ฝ”๋“œ: ๋ชจ๋“  API๋งˆ๋‹ค ๋น„์Šทํ•œ ์ฝ”๋“œ ๋ฐ˜๋ณต
  4. ์‹ค์ˆ˜ ๊ฐ€๋Šฅ์„ฑ: URL ์˜คํƒ€, ์ž˜๋ชป๋œ ํŒŒ๋ผ๋ฏธํ„ฐ ๋“ฑ
  5. ์œ ์ง€๋ณด์ˆ˜ ์–ด๋ ค์›€: API ๋ณ€๊ฒฝ ์‹œ ๋ชจ๋“  ํ˜ธ์ถœ ์ง€์  ์ˆ˜์ • ํ•„์š”

ํ•ด๊ฒฐ: ์ž๋™ ์ƒ์„ฑ์˜ ์žฅ์ 

Sonamu๋Š” ๋ฐฑ์—”๋“œ์˜ @api ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ํƒ€์ž… ์•ˆ์ „ํ•œ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ž๋™ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ž๋™ ์ƒ์„ฑ ํด๋ผ์ด์–ธํŠธ ์˜ˆ์‹œ:
์žฅ์ :
  1. โœจ ์™„์ „ํ•œ ํƒ€์ž… ์•ˆ์ „์„ฑ: ๋ฐฑ์—”๋“œ ํƒ€์ž…์ด ํ”„๋ก ํŠธ์—”๋“œ์— ๊ทธ๋Œ€๋กœ ๋ฐ˜์˜
  2. โœจ ์ฆ‰๊ฐ์ ์ธ ์—๋Ÿฌ ๋ฐœ๊ฒฌ: ์ปดํŒŒ์ผ ํƒ€์ž„์— API ๋ณ€๊ฒฝ ๊ฐ์ง€
  3. โœจ ์ž๋™ ์™„์„ฑ: IDE๊ฐ€ API ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ์‘๋‹ต ํƒ€์ž… ์ž๋™ ์ œ์•ˆ
  4. โœจ Namespace ๊ธฐ๋ฐ˜: ๊น”๋”ํ•œ ๊ตฌ์กฐ, import ๊ฐ„ํŽธ
  5. โœจ ๋‹จ์ผ ์ง„์‹ค ๊ณต๊ธ‰์›: ๋ฐฑ์—”๋“œ๊ฐ€ API ๋ช…์„ธ์˜ ์œ ์ผํ•œ ์†Œ์Šค
**๋‹จ์ผ ์ง„์‹ค ๊ณต๊ธ‰์› (Single Source of Truth)**์ด๋ž€ ์‹œ์Šคํ…œ์˜ ๋ชจ๋“  ์ •๋ณด๊ฐ€ ํ•˜๋‚˜์˜ ์†Œ์Šค์—์„œ ํŒŒ์ƒ๋˜๋Š” ์›์น™์ž…๋‹ˆ๋‹ค. Sonamu์—์„œ๋Š” ๋ฐฑ์—”๋“œ์˜ @api ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์œ ์ผํ•œ API ๋ช…์„ธ์ด๋ฉฐ, ํ”„๋ก ํŠธ์—”๋“œ๋Š” ์ด๋ฅผ ๋”ฐ๋ผ๊ฐ‘๋‹ˆ๋‹ค.

Service ์ƒ์„ฑ ๊ณผ์ •

1๋‹จ๊ณ„: ๋ฐฑ์—”๋“œ API ์ •์˜

๋ฐฑ์—”๋“œ์—์„œ @api ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ API๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
์ด API ์ •์˜๊ฐ€ ๋ชจ๋“  ๊ฒƒ์˜ ์‹œ์ž‘์ ์ž…๋‹ˆ๋‹ค. ํƒ€์ž… ์ •๋ณด, ํŒŒ๋ผ๋ฏธํ„ฐ, ์‘๋‹ต ํ˜•์‹ ๋ชจ๋‘ ์—ฌ๊ธฐ์— ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

2๋‹จ๊ณ„: TypeScript AST ํŒŒ์‹ฑ

Sonamu๋Š” TypeScript ์ปดํŒŒ์ผ๋Ÿฌ API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค. ๋ถ„์„ ๊ณผ์ •:
ํ•ต์‹ฌ ๊ฐœ๋…:
  • AST (Abstract Syntax Tree): ์ฝ”๋“œ๋ฅผ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ํ‘œํ˜„ํ•œ ๊ฒƒ
  • ํƒ€์ž… ์ถ”์ถœ: TypeScript์˜ ํƒ€์ž… ์‹œ์Šคํ…œ์—์„œ ์ •ํ™•ํ•œ ํƒ€์ž… ์ •๋ณด ํš๋“
  • ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ˆ˜์ง‘: ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์˜ต์…˜, Guards, ์ฃผ์„ ๋“ฑ ๋ชจ๋“  ์ •๋ณด ์ˆ˜์ง‘

3๋‹จ๊ณ„: Namespace Service ์ƒ์„ฑ

์ˆ˜์ง‘๋œ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ Namespace ๊ธฐ๋ฐ˜ Service๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ƒ์„ฑ๋˜๋Š” ์ฝ”๋“œ (services.generated.ts):
Namespace ๊ตฌ์กฐ์˜ ์žฅ์ :
  • ๊ฐ„๊ฒฐํ•จ: ํด๋ž˜์Šค๋ณด๋‹ค ๊ฐ„๋‹จ (new ๋ถˆํ•„์š”)
  • ์ •์  ๋ฉ”์„œ๋“œ: ์ƒํƒœ ๊ด€๋ฆฌ ๋ถˆํ•„์š”
  • Tree-shaking: ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜๋Š” ๋ฒˆ๋“ค์—์„œ ์ œ์™ธ
  • Import ๊ฐ„ํŽธ: import { UserService } from "./services.generated"

4๋‹จ๊ณ„: TanStack Query Hook ์ƒ์„ฑ

React์—์„œ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” Hook๋„ ์ž๋™ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
TanStack Query ํ†ตํ•ฉ์˜ ์žฅ์ :
  • ์ž๋™ ์บ์‹ฑ
  • ์ž๋™ ์žฌ๊ฒ€์ฆ
  • ๋กœ๋”ฉ/์—๋Ÿฌ ์ƒํƒœ ์ž๋™ ๊ด€๋ฆฌ
  • ์กฐ๊ฑด๋ถ€ ํŽ˜์นญ ์ง€์›
  • ๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ ์ง€์›

์ƒ์„ฑ๋œ Service์˜ ๊ตฌ์กฐ

fetch ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜

๋ชจ๋“  Service๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๊ณตํ†ต fetch ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
fetch ํ•จ์ˆ˜์˜ ์—ญํ• :
  • Axios ํ˜ธ์ถœ ๋ž˜ํ•‘: options๋ฅผ Axios์— ์ „๋‹ฌ
  • ์ž๋™ ์‘๋‹ต ์ถ”์ถœ: res.data๋ฅผ ๋ฐ”๋กœ ๋ฐ˜ํ™˜
  • ์—๋Ÿฌ ๋ณ€ํ™˜: Axios ์—๋Ÿฌ โ†’ SonamuError
  • Zod ์ด์Šˆ ์ฒ˜๋ฆฌ: ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์—๋Ÿฌ๋ฅผ ํƒ€์ž… ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ
AxiosRequestConfig ํŒŒ๋ผ๋ฏธํ„ฐ:

Subset ์‹œ์Šคํ…œ

Sonamu์˜ ๋…ํŠนํ•œ ๊ธฐ๋Šฅ์ธ Subset ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค. Subset์ด๋ž€? ์—”ํ‹ฐํ‹ฐ์˜ ์—ฌ๋Ÿฌ ๋ณ€ํ˜•(subset)์„ ์ •์˜ํ•˜์—ฌ ํ•„์š”ํ•œ ํ•„๋“œ๋งŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค.
Subset์˜ ์žฅ์ :
  1. ์„ฑ๋Šฅ: ํ•„์š”ํ•œ ํ•„๋“œ๋งŒ ์กฐํšŒํ•˜์—ฌ ๋„คํŠธ์›Œํฌ ๋น„์šฉ ์ ˆ๊ฐ
  2. ํƒ€์ž… ์•ˆ์ „: ๊ฐ Subset๋งˆ๋‹ค ์ •ํ™•ํ•œ ํƒ€์ž… ๋ฐ˜ํ™˜
  3. ๋ช…์‹œ์„ฑ: ์–ด๋–ค ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ์ง€ ์ฝ”๋“œ์—์„œ ๋ช…ํ™•ํžˆ ํ‘œํ˜„
  4. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ตœ์ ํ™”: SELECT ์ ˆ์— ํ•„์š”ํ•œ ์ปฌ๋Ÿผ๋งŒ ํฌํ•จ
Subset ๋„ค์ด๋ฐ ๊ทœ์น™:
  • A: ๊ธฐ๋ณธ ํ•„๋“œ (id, ํ•ต์‹ฌ ์ •๋ณด)
  • B: ์ค‘๊ฐ„ ํ•„๋“œ (A + ์ถ”๊ฐ€ ์ •๋ณด)
  • C: ์ „์ฒด ํ•„๋“œ (๋ชจ๋“  ์ปฌ๋Ÿผ, ํƒ€์ž„์Šคํƒฌํ”„ ํฌํ•จ)

ํƒ€์ž… ์•ˆ์ „์„ฑ์˜ ์‹ค์ œ

์ปดํŒŒ์ผ ํƒ€์ž„ ๊ฒ€์ฆ

๋ฐฑ์—”๋“œ API๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ์ปดํŒŒ์ผ ํƒ€์ž„์— ์ฆ‰์‹œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ ๋ณ€๊ฒฝ:
ํ”„๋ก ํŠธ์—”๋“œ ์—๋Ÿฌ:
์ด๋Š” ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์œผ๋กœ ๋Œ์–ด์˜ฌ๋ ค ๋ฒ„๊ทธ๋ฅผ ์‚ฌ์ „์— ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

IDE ์ž๋™ ์™„์„ฑ

ํƒ€์ž… ์ •๋ณด ๋•๋ถ„์— IDE๊ฐ€ ๊ฐ•๋ ฅํ•œ ์ž๋™ ์™„์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ ์›Œํฌํ”Œ๋กœ์šฐ

๋ฐฑ์—”๋“œ ์šฐ์„  ๊ฐœ๋ฐœ

Sonamu์˜ ์ž๋™ ์ƒ์„ฑ์€ ๋ฐฑ์—”๋“œ ์šฐ์„ (Backend-First) ๊ฐœ๋ฐœ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ์›Œํฌํ”Œ๋กœ์šฐ: ์žฅ์ :
  • ๋ฐฑ์—”๋“œ์™€ ํ”„๋ก ํŠธ์—”๋“œ์˜ ๊ณ„์•ฝ(Contract)์ด ๋ช…ํ™•
  • ํƒ€์ž… ๋ถˆ์ผ์น˜๋กœ ์ธํ•œ ๋ฒ„๊ทธ ์›์ฒœ ์ฐจ๋‹จ
  • API ๋ฌธ์„œ ์ž๋™ ์ƒ์„ฑ (Service๊ฐ€ ๊ณง ๋ฌธ์„œ)
  • ํ˜‘์—… ํšจ์œจ์„ฑ ํ–ฅ์ƒ

๊ฐœ๋ฐœ ์‹œ ์žฌ์ƒ์„ฑ

API๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค Service๋ฅผ ์žฌ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ฃผ์˜์‚ฌํ•ญ: - ์ƒ์„ฑ๋œ Service ํŒŒ์ผ(services.generated.ts)์€ ์ ˆ๋Œ€ ์ˆ˜๋™ ์ˆ˜์ • ๊ธˆ์ง€ - ์ˆ˜์ •์ด ํ•„์š”ํ•˜๋ฉด ๋ฐฑ์—”๋“œ์—์„œ ์ˆ˜์ • ํ›„ ์žฌ์ƒ์„ฑ - ์ƒ์„ฑ ํŒŒ์ผ์„ .gitignore์— ์ถ”๊ฐ€ํ• ์ง€ ํŒ€์—์„œ ๊ฒฐ์ • - ์ถ”๊ฐ€ํ•˜๋ฉด: ๊ฐ์ž ๋กœ์ปฌ์—์„œ ์ƒ์„ฑ - ์ถ”๊ฐ€ ์•ˆํ•˜๋ฉด: Git์œผ๋กœ ๊ณต์œ  (๋นŒ๋“œ ์‹œ๊ฐ„ ๋‹จ์ถ•)

์‹ค์ œ ์‚ฌ์šฉ ์˜ˆ์‹œ

๊ธฐ๋ณธ ์‚ฌ์šฉ

React์—์„œ ์‚ฌ์šฉ (TanStack Query Hook)

์กฐ๊ฑด๋ถ€ ํŽ˜์นญ

๊ณ ๊ธ‰ ๊ธฐ๋Šฅ

qs.stringify ์‚ฌ์šฉ

GET ์š”์ฒญ์˜ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ง๋ ฌํ™”ํ•  ๋•Œ qs ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
qs๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ :
  • ์ค‘์ฒฉ ๊ฐ์ฒด ์ง€์› (filters[status]=active)
  • ๋ฐฐ์—ด ์ง๋ ฌํ™” ์ง€์› (ids[]=1&ids[]=2)
  • ๋ฐฑ์—”๋“œ์˜ ํŒŒ์‹ฑ ๋ฐฉ์‹๊ณผ ์ผ์น˜

์—๋Ÿฌ ์ฒ˜๋ฆฌ

SonamuError๋ฅผ ํƒ€์ž… ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

Query Options ์žฌ์‚ฌ์šฉ

Prefetching

์ฃผ์˜์‚ฌํ•ญ

Service ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ: 1. ์ƒ์„ฑ๋œ Service ํŒŒ์ผ(services.generated.ts)์€ ์ ˆ๋Œ€ ์ˆ˜๋™ ์ˆ˜์ • ๊ธˆ์ง€ 2. Subset ํŒŒ๋ผ๋ฏธํ„ฐ ํ•„์ˆ˜: getUser("A", id) ์ฒ˜๋Ÿผ subset ์ง€์ • ํ•„์š” 3. Namespace์ด๋ฏ€๋กœ new ๋ถˆํ•„์š”: UserService.getUser() ์ง์ ‘ ํ˜ธ์ถœ 4. TanStack Query Hook์€ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ๋งŒ ํ˜ธ์ถœ 5. ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์‹œ isSonamuError() ํƒ€์ž… ๊ฐ€๋“œ ์‚ฌ์šฉ 6. qs.stringify()๋Š” ๋ณต์žกํ•œ ๊ฐ์ฒด ์ง๋ ฌํ™” ์‹œ ์‚ฌ์šฉ

๋‹ค์Œ ๋‹จ๊ณ„

Service ์‚ฌ์šฉํ•˜๊ธฐ

์ƒ์„ฑ๋œ Service ํ™œ์šฉ๋ฒ•

TanStack Query Hook

React์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ

Creating APIs

@api ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ

Subset System

Subset ์‹œ์Šคํ…œ