9148c358d0
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를 Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류. - 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로 자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거, 동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거. - 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming, Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business, Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로, 나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는 title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백). 원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지. - 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서. - 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는 지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지. - Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경. - 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
6.5 KiB
6.5 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| api-openapi-spec | OpenAPI / Swagger — Schema-first vs Code-first | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
OpenAPI
API contract 표준. Schema → Type generation, mock server, client SDK, docs. Schema-first 또는 Code-first. Hono / ts-rest / oRPC 가 modern code-first.
📖 핵심 개념
- OpenAPI 3.1: 표준 spec.
- Schema-first: yaml/json 먼저 → 코드 생성.
- Code-first: 코드의 type → spec 자동.
- Server / client SDK 자동.
💻 코드 패턴
Schema-first (yaml)
openapi: 3.1.0
info:
title: Acme API
version: 1.0.0
paths:
/orders:
get:
summary: List orders
parameters:
- { name: limit, in: query, schema: { type: integer, default: 20 } }
- { name: cursor, in: query, schema: { type: string } }
responses:
'200':
description: ok
content:
application/json:
schema:
$ref: '#/components/schemas/OrderList'
post:
summary: Create order
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/CreateOrder' }
responses:
'201':
description: created
content:
application/json:
schema: { $ref: '#/components/schemas/Order' }
'400':
description: validation error
content:
application/problem+json:
schema: { $ref: '#/components/schemas/Problem' }
components:
schemas:
Order:
type: object
required: [id, items, total]
properties:
id: { type: string, format: uuid }
items:
type: array
items: { $ref: '#/components/schemas/OrderItem' }
total: { type: string }
status: { type: string, enum: [open, paid, shipped] }
Problem:
type: object
required: [type, title, status]
properties:
type: { type: string, format: uri }
title: { type: string }
status: { type: integer }
detail: { type: string }
코드 생성
# Server stub
openapi-generator-cli generate -i api.yaml -g typescript-node-server -o server/
# Client SDK
openapi-generator-cli generate -i api.yaml -g typescript-axios -o client/
# 또는 modern: openapi-typescript
npx openapi-typescript api.yaml -o api-types.ts
import type { paths } from './api-types';
type CreateOrderRequest = paths['/orders']['post']['requestBody']['content']['application/json'];
type OrderResponse = paths['/orders']['post']['responses']['201']['content']['application/json'];
Code-first — Hono + zod-openapi
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi';
const app = new OpenAPIHono();
const route = createRoute({
method: 'post',
path: '/orders',
request: {
body: {
content: { 'application/json': { schema: CreateOrderSchema } },
},
},
responses: {
201: {
content: { 'application/json': { schema: OrderSchema } },
description: 'Created',
},
},
});
app.openapi(route, async (c) => {
const data = c.req.valid('json'); // typed
const order = await createOrder(data);
return c.json(order, 201);
});
// Spec 노출
app.doc('/openapi.json', { openapi: '3.1.0', info: { title: 'API', version: '1.0' } });
Code-first — ts-rest
import { initContract } from '@ts-rest/core';
const c = initContract();
export const contract = c.router({
createOrder: {
method: 'POST',
path: '/orders',
body: CreateOrderSchema,
responses: { 201: OrderSchema, 400: ProblemSchema },
},
});
// Server (Express / Fastify / Hono)
import { initServer } from '@ts-rest/express';
const router = initServer().router(contract, {
createOrder: async ({ body }) => ({ status: 201, body: await create(body) }),
});
// Client (auto-typed)
import { initClient } from '@ts-rest/core';
const api = initClient(contract, { baseUrl: '...' });
const r = await api.createOrder({ body: { items: [...] } });
→ Frontend / backend 가 type 공유.
Mock server (fast prototyping)
# Prism — OpenAPI mock
prism mock api.yaml --port 4010
→ Backend 만들기 전에 frontend 시작.
Docs UI
// Swagger UI
import swaggerUi from 'swagger-ui-express';
app.use('/docs', swaggerUi.serve, swaggerUi.setup(spec));
// Scalar (modern, beautiful)
import { apiReference } from '@scalar/express-api-reference';
app.use('/docs', apiReference({ spec: { url: '/openapi.json' } }));
// Stoplight Elements
Validation (Hono / Express middleware)
// Express
import OpenApiValidator from 'express-openapi-validator';
app.use(OpenApiValidator.middleware({ apiSpec: 'api.yaml' }));
// 자동 validate body / query / response
Lint (Spectral)
npx spectral lint api.yaml
# 표준 / 일관성 검사
# .spectral.yml
rules:
operation-tag-defined: warn
operation-success-response: error
no-unresolved-refs: error
Diff (breaking change)
npx oasdiff diff old.yaml new.yaml --breaking-only
# CI 에서 PR 마다
Code-first vs Schema-first
Schema-first:
+ Single source of truth
+ Multi-language (server / client)
- Sync 어려움 (yaml 과 코드)
Code-first:
+ TS type 가 진실
+ Hot reload
- 다른 언어 client = generate 필요
🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| TS only fullstack | ts-rest / oRPC / Hono RPC / tRPC |
| 다양한 client 언어 | Schema-first OpenAPI |
| Public API | OpenAPI + Scalar docs |
| Mock first | Schema-first + Prism |
| Strong type 일급 | Code-first |
| 빠른 prototype | Code-first |
❌ 안티패턴
- Spec 과 코드 drift: schema-first 의 위험. CI 에서 검증.
- 모든 endpoint 200 만 명시: 4xx / 5xx 같이.
- Schema 안 example: 사용자 모름.
- Auth 누락 (security scheme): 명시.
- Generated client 직접 변경: 다음 generate 시 잃음.
- OpenAPI 안 서버 검증: client 만 — server bypass 가능.
- Versioning 없는 spec 변경: breaking.
🤖 LLM 활용 힌트
- TS = ts-rest / Hono RPC.
- 다중 언어 = OpenAPI yaml + generators.
- Spectral lint + oasdiff CI.