Agent skill
api-contract-design
Design APIs using schema-first approach with OpenAPI/Swagger. Use when creating new APIs, documenting existing ones, or when frontend/backend teams need to work in parallel. Covers OpenAPI spec, validation, and code generation.
Install this agent skill to your Project
npx add-skill https://github.com/aiskillstore/marketplace/tree/main/skills/doyajin174/api-contract-design
Metadata
Additional technical details for this skill
- author
- antigravity-team
- version
- 1.0
SKILL.md
API Contract Design
OpenAPI(Swagger) 기반 스키마 우선 API 설계 스킬입니다.
Core Principle
"코드보다 계약(Contract)이 먼저다." "프론트엔드와 백엔드가 동시에 개발할 수 있게 API를 먼저 정의한다."
Schema-First vs Code-First
| 접근법 | 장점 | 단점 |
|---|---|---|
| Schema-First (권장) | 병렬 개발 가능, 명확한 계약 | 초기 설계 시간 필요 |
| Code-First | 빠른 시작 | 문서와 코드 불일치 위험 |
OpenAPI 기본 구조
openapi.yaml
openapi: 3.1.0
info:
title: My API
version: 1.0.0
description: API for My Application
servers:
- url: https://api.example.com/v1
description: Production
- url: http://localhost:3000/api
description: Development
paths:
/users:
get:
summary: Get all users
operationId: getUsers
tags:
- Users
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/UserListResponse'
'401':
$ref: '#/components/responses/Unauthorized'
post:
summary: Create a new user
operationId: createUser
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
responses:
'201':
description: User created
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
$ref: '#/components/responses/BadRequest'
'409':
description: Email already exists
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/users/{userId}:
get:
summary: Get user by ID
operationId: getUserById
tags:
- Users
parameters:
- name: userId
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
$ref: '#/components/responses/NotFound'
components:
schemas:
User:
type: object
required:
- id
- email
- name
- createdAt
properties:
id:
type: string
format: uuid
email:
type: string
format: email
name:
type: string
minLength: 1
maxLength: 100
avatarUrl:
type: string
format: uri
nullable: true
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
CreateUserRequest:
type: object
required:
- email
- name
- password
properties:
email:
type: string
format: email
name:
type: string
minLength: 1
maxLength: 100
password:
type: string
minLength: 8
UserListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
pagination:
$ref: '#/components/schemas/Pagination'
Pagination:
type: object
required:
- page
- limit
- total
- totalPages
properties:
page:
type: integer
limit:
type: integer
total:
type: integer
totalPages:
type: integer
Error:
type: object
required:
- code
- message
properties:
code:
type: string
message:
type: string
details:
type: object
responses:
BadRequest:
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- BearerAuth: []
폴더 구조
api/
├── openapi.yaml # 메인 스펙
├── paths/ # 엔드포인트별 분리
│ ├── users.yaml
│ ├── posts.yaml
│ └── auth.yaml
├── schemas/ # 스키마 분리
│ ├── user.yaml
│ ├── post.yaml
│ └── common.yaml
└── generated/ # 자동 생성 코드
├── types.ts
└── client.ts
분리된 스펙 (paths/users.yaml)
# api/paths/users.yaml
/users:
get:
$ref: '../operations/users/getUsers.yaml'
post:
$ref: '../operations/users/createUser.yaml'
메인 스펙에서 참조
# api/openapi.yaml
paths:
/users:
$ref: './paths/users.yaml#/~1users'
TypeScript 타입 생성
openapi-typescript
npm install -D openapi-typescript
# 타입 생성
npx openapi-typescript ./api/openapi.yaml -o ./src/types/api.ts
생성된 타입 사용
import type { paths, components } from './types/api';
type User = components['schemas']['User'];
type CreateUserRequest = components['schemas']['CreateUserRequest'];
// API 응답 타입
type GetUsersResponse = paths['/users']['get']['responses']['200']['content']['application/json'];
API 클라이언트 생성
openapi-fetch (권장)
npm install openapi-fetch
// lib/api-client.ts
import createClient from 'openapi-fetch';
import type { paths } from './types/api';
export const api = createClient<paths>({
baseUrl: process.env.NEXT_PUBLIC_API_URL,
});
// 사용
const { data, error } = await api.GET('/users', {
params: {
query: { page: 1, limit: 20 },
},
});
const { data: user } = await api.POST('/users', {
body: {
email: 'user@example.com',
name: 'John',
password: 'password123',
},
});
Orval (코드 생성)
npm install -D orval
// orval.config.ts
export default {
api: {
input: './api/openapi.yaml',
output: {
mode: 'tags-split',
target: './src/api',
schemas: './src/api/schemas',
client: 'react-query',
},
},
};
요청 검증
Zod + OpenAPI
// 스키마에서 Zod 스키마 생성
import { z } from 'zod';
// OpenAPI 스펙 기반 Zod 스키마
export const CreateUserRequestSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
password: z.string().min(8),
});
// API 라우트에서 검증
export async function POST(request: Request) {
const body = await request.json();
const result = CreateUserRequestSchema.safeParse(body);
if (!result.success) {
return Response.json(
{ code: 'VALIDATION_ERROR', message: result.error.message },
{ status: 400 }
);
}
// result.data는 타입 안전
const user = await createUser(result.data);
return Response.json(user, { status: 201 });
}
API 문서 UI
Swagger UI
npm install swagger-ui-react
// app/api-docs/page.tsx
'use client';
import SwaggerUI from 'swagger-ui-react';
import 'swagger-ui-react/swagger-ui.css';
export default function ApiDocs() {
return <SwaggerUI url="/api/openapi.yaml" />;
}
Scalar (모던 대안)
npm install @scalar/nextjs-api-reference
// app/api-docs/page.tsx
import { ApiReference } from '@scalar/nextjs-api-reference';
export default function ApiDocs() {
return (
<ApiReference
configuration={{
spec: {
url: '/api/openapi.yaml',
},
}}
/>
);
}
버전 관리
URL 버전 관리
servers:
- url: https://api.example.com/v1
- url: https://api.example.com/v2
헤더 버전 관리
parameters:
- name: API-Version
in: header
schema:
type: string
enum: ['2024-01-01', '2024-06-01']
Workflow
Schema-First 개발 흐름
1. API 스펙 작성 (openapi.yaml)
↓
2. 팀 리뷰 (PR)
↓
3. 타입 생성 (openapi-typescript)
↓
4. 병렬 개발
- Frontend: Mock 서버로 개발
- Backend: 스펙 기반 구현
↓
5. 통합 테스트
Mock 서버
# Prism (Stoplight)
npm install -D @stoplight/prism-cli
# Mock 서버 실행
npx prism mock ./api/openapi.yaml
Checklist
스펙 작성
- 모든 엔드포인트 정의
- Request/Response 스키마 정의
- 에러 응답 정의
- 인증 방식 정의
- 예제 데이터 포함
타입 안전성
- TypeScript 타입 생성
- 요청 검증 (Zod)
- 응답 타입 체크
문서화
- API 문서 UI 제공
- 변경 이력 관리
- 버전 관리 전략
References
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
perigon-backend
Perigon ASP.NET Core + EF Core + Aspire conventions
perigon-agent
Pointers for Copilot/agents to apply Perigon conventions
perigon-angular
Angular 21+ standalone/Material/signal conventions for Perigon WebApp
fastapi-mastery
Comprehensive FastAPI development skill covering REST API creation, routing, request/response handling, validation, authentication, database integration, middleware, and deployment. Use when working with FastAPI projects, building APIs, implementing CRUD operations, setting up authentication/authorization, integrating databases (SQL/NoSQL), adding middleware, handling WebSockets, or deploying FastAPI applications. Triggered by requests involving .py files with FastAPI code, API endpoint creation, Pydantic models, or FastAPI-specific features.
context7-efficient
Token-efficient library documentation fetcher using Context7 MCP with 86.8% token savings through intelligent shell pipeline filtering. Fetches code examples, API references, and best practices for JavaScript, Python, Go, Rust, and other libraries. Use when users ask about library documentation, need code examples, want API usage patterns, are learning a new framework, need syntax reference, or troubleshooting with library-specific information. Triggers include questions like "Show me React hooks", "How do I use Prisma", "What's the Next.js routing syntax", or any request for library/framework documentation.
browser-use
Browser automation using Playwright MCP. Navigate websites, fill forms, click elements, take screenshots, and extract data. Use when tasks require web browsing, form submission, web scraping, UI testing, or any browser interaction.
Didn't find tool you were looking for?