openapi について
API の設計者や開発者向けの OpenAPI 基礎知識スキルです。仕様の構造、スキーマ、品質確認、コード生成を扱い、API 契約の管理やフロントエンドでの利用に役立ちます。
主な機能
- 01OpenAPI の基本構造の紹介
- 02スキーマ型と検証の解説
- 03仕様設計のアンチパターン
- 04仕様検証と契約テストの例
- 05TypeScript 型とクライアント生成の説明
活用シーン
- 01API のリクエストとレスポンス契約の定義
- 02仕様の検証とエラーの調査
- 03フロントエンド向け型やクライアントの生成
MCP 対応
README では、OpenAPI の詳細ドキュメント取得先として mcp__documentation__fetch_docs に言及しています。スキル自体の MCP 接続方法は説明されていません。
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ claude-dev-suite/ claude-dev-suite --skill openapiインストール後、Claude Code で/openapiを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
quick-ref/frontend-integration.mdspecification.mdtools.md詳細
OpenAPI コアナレッジ
詳細なナレッジ:包括的なドキュメントを参照するには、テクノロジーに
openapiを指定してmcp__documentation__fetch_docsを使用してください。
基本構造
openapi: 3.1.0
info:
title: User API
version: 1.0.0
description: API for managing users
servers:
- url: https://api.example.com/v1
paths:
/users:
get:
summary: List users
operationId: listUsers
parameters:
- name: limit
in: query
schema:
type: integer
default: 20
responses:
'200':
description: List of users
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
post:
summary: Create user
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUser'
responses:
'201':
description: User created
content:
application/json:
schema:
$ref: '#/components/schemas/User'
/users/{id}:
get:
summary: Get user by ID
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: User found
'404':
description: User not found
components:
schemas:
User:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
format: email
required: [id, name, email]
CreateUser:
type: object
properties:
name:
type: string
email:
type: string
format: email
required: [name, email]
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- bearerAuth: []
スキーマの型
# String with validation
type: string
minLength: 1
maxLength: 100
pattern: '^[a-zA-Z]+$'
format: email | date | date-time | uri | uuid
# Number
type: integer
minimum: 0
maximum: 100
# Enum
type: string
enum: [active, inactive, pending]
# Array
type: array
items:
type: string
minItems: 1
maxItems: 10
# Object
type: object
additionalProperties: false
このスキルを使用しない場合
- GraphQL API のドキュメント作成(
graphqlスキルを使用) - tRPC の型安全な API(
trpcスキルを使用) - API クライアントの生成(
openapi-codegenスキルを使用) - Spring Boot API のドキュメント作成(
springdoc-openapiスキルを使用) - コードファーストの API 開発(アノテーション/デコレーターの使用を検討)
アンチパターン
| アンチパターン | 問題点 | 解決策 |
|---|---|---|
| レスポンススキーマがない | 型安全性がなく、ドキュメントの質が低下します | すべてのレスポンスにスキーマを定義します |
| スキーマに例がない | API を理解しにくくなります | すべてのスキーマに example または examples を追加します |
object のみを使用し、プロパティを指定しない | 型情報が失われます | 型を指定した明示的なプロパティを定義します |
| エラーレスポンスを定義しない | API コントラクトが不完全になります | 4xx および 5xx のレスポンスを記述します |
| サーバー URL をハードコードする | 仕様に環境固有の設定が含まれます | サーバー変数または複数のサーバーを使用します |
required フィールドがない | API コントラクトが曖昧になります | すべての必須フィールドを明示的に指定します |
| スキーマ定義が重複している | 保守が非常に困難になります | $ref とコンポーネントを使用します |
| セキュリティスキームが定義されていない | 認証方法が不明確になります | コンポーネントにセキュリティスキームを定義します |
operationId がない | コード生成の質が低下します | 各エンドポイントに一意の operationId を追加します |
どこでも additionalProperties: true を使用する | バリデーションの利点が失われます | 必要な場合を除き、false に設定します |
トラブルシューティングのクイックガイド
| 問題 | 考えられる原因 | 解決策 |
|---|---|---|
| 仕様のバリデーションエラー | YAML/JSON の構文が無効です | @redocly/cli lint または Swagger Editor を使用します |
| コード生成に失敗する | operationId がない、または refs が無効です | operationId を追加し、すべての $refs が解決されることを確認します |
| Swagger UI が読み込まれない | CORS または仕様が無効です | ブラウザーのコンソールを確認し、仕様を検証します |
| 生成コードの型エラー | スキーマと実装が一致していません | スキーマが実際の API レスポンスと一致することを確認します |
| 生成された型にフィールドがない | スキーマにすべてのプロパティが定義されていません | スキーマ定義にすべてのプロパティを追加します |
| 循環参照エラー | スキーマが自己参照しています | allOf を使用するか、スキーマ構造をリファクタリングします |
| 例のバリデーションに失敗する | 例がスキーマと一致していません | 例がスキーマの制約に準拠していることを確認します |
| Swagger UI で認証が使えない | セキュリティが設定されていません | securitySchemes とセキュリティ要件を追加します |
本番環境への準備
エラーレスポンスを完全に定義する
components:
schemas:
Error:
type: object
properties:
code:
type: string
example: 'NOT_FOUND'
message:
type: string
example: 'User not found'
details:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string
required: [code, message]
responses:
BadRequest:
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
code: 'VALIDATION_ERROR'
message: 'Invalid input'
details:
- field: 'email'
message: 'Invalid email format'
Unauthorized:
description: Authentication required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
RateLimited:
description: Too many requests
headers:
X-RateLimit-Limit:
schema:
type: integer
X-RateLimit-Remaining:
schema:
type: integer
X-RateLimit-Reset:
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
paths:
/users:
post:
responses:
'201':
description: Created
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/RateLimited'
ページネーション
components:
schemas:
PaginatedResponse:
type: object
properties:
data:
type: array
items: {}
pagination:
type: object
properties:
page:
type: integer
limit:
type: integer
total:
type: integer
totalPages:
type: integer
parameters:
PageParam:
name: page
in: query
schema:
type: integer
minimum: 1
default: 1
LimitParam:
name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
paths:
/users:
get:
parameters:
- $ref: '#/components/parameters/PageParam'
- $ref: '#/components/parameters/LimitParam'
responses:
'200':
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/PaginatedResponse'
- type: object
properties:
data:
items:
$ref: '#/components/schemas/User'
コード生成
# Generate TypeScript types
npx openapi-typescript ./openapi.yaml -o ./src/types/api.ts
# Generate client SDK
npx @openapitools/openapi-generator-cli generate \
-i openapi.yaml \
-g typescript-fetch \
-o ./src/api-client
# Validate spec
npx @redocly/cli lint openapi.yaml
// Generated type usage
import type { paths, components } from './types/api';
type User = components['schemas']['User'];
type CreateUserRequest = paths['/users']['post']['requestBody']['content']['application/json'];
type UserListResponse = paths['/users']['get']['responses']['200']['content']['application/json'];
テスト
// Contract testing with OpenAPI
import SwaggerParser from '@apidevtools/swagger-parser';
import { expect, test } from 'vitest';
test('OpenAPI spec is valid', async () => {
const api = await SwaggerParser.validate('./openapi.yaml');
expect(api.info.title).toBeDefined();
});
// API response validation
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
const ajv = new Ajv({ strict: false });
addFormats(ajv);
test('GET /users returns valid response', async () => {
const response = await fetch('/api/users');
const data = await response.json();
const validate = ajv.compile(userListSchema);
expect(validate(data)).toBe(true);
});
監視メトリクス
| メトリクス | 目標 |
|---|---|
| 仕様のバリデーションエラー | 0 |
| 破壊的変更 | 0(semver) |
| ドキュメントのカバレッジ | 100% |
| 例のカバレッジ | > 80% |
チェックリスト
- 標準のエラーレスポンススキーマ
- ページネーションパラメーターの定義
- すべてのレスポンスのドキュメント化
- セキュリティスキームの定義
- リクエスト/レスポンスの例
- 再利用可能なコンポーネント
- コード生成の設定
- CI での仕様のバリデーション
- コントラクトテスト
- バージョニング戦略
フロントエンドとの統合
OpenAPI 仕様はフロントエンドアプリケーションで利用し、型安全なクライアントを生成できます。
ワークフロー
OpenAPI Spec → Code Generation → Type-Safe Client → Frontend App
関連スキル
| スキル | 用途 |
|---|---|
| HTTP クライアント | Axios、Fetch、ky、ofetch のパターン |
| OpenAPI コード生成 | 仕様からクライアントを生成 |
| 型安全な API | エンドツーエンドの型安全性 |
クライアントをすばやく生成する
# Generate TypeScript types only
npx openapi-typescript ./openapi.yaml -o ./src/types/api.ts
# Generate full client
npx @openapitools/openapi-generator-cli generate \
-i openapi.yaml \
-g typescript-fetch \
-o ./src/api-client
# swagger-typescript-api (simpler)
npx swagger-typescript-api -p ./openapi.yaml -o ./src/api --axios
フロントエンドでの型の使用
import type { paths, components } from './types/api';
import { createApiClient } from './api-client';
// Type-safe request/response
type User = components['schemas']['User'];
type CreateUserBody = paths['/users']['post']['requestBody']['content']['application/json'];
type UsersResponse = paths['/users']['get']['responses']['200']['content']['application/json'];
// With generated client
const api = createApiClient({ baseUrl: '/api' });
const users = await api.users.list(); // Fully typed
リファレンスドキュメント
コメント
Markdown 対応