Zod × OpenAPI:`zod-to-openapi` で契約からドキュメントを自動生成

TypeScript でバリデーションを実装する際、Zod を使うとスキーマ定義から型を自動生成できて便利ですよね。しかし API 開発では、同じようなスキーマを OpenAPI ドキュメントにも書く必要があり、二重管理になってしまいます。
実は、zod-to-openapi
というライブラリを使えば、Zod スキーマから OpenAPI ドキュメントを自動生成できるんです。これにより、バリデーションとドキュメントの一元管理が実現でき、保守性が大幅に向上します。
背景
API 開発における二重管理の課題
API 開発では、以下のような複数の定義を管理する必要があります。
- TypeScript の型定義:静的型チェックのため
- ランタイムバリデーション:実行時のデータ検証
- API ドキュメント:Swagger/OpenAPI 仕様書
従来のアプローチでは、これらを別々に記述・管理していました。そのため、API 仕様を変更するたびに、複数箇所を修正する手間が発生していたのです。
以下の図は、従来の開発フローにおける課題を示しています。
mermaidflowchart TB
dev["開発者"] -->|手動定義| types["TypeScript 型"]
dev -->|手動定義| validation["バリデーションロジック"]
dev -->|手動定義| openapi["OpenAPI 仕様書"]
types -.->|不一致リスク| validation
validation -.->|不一致リスク| openapi
style types fill:#e1f5ff
style validation fill:#fff4e1
style openapi fill:#ffe1e1
上図のように、3 つの定義が独立しているため、変更時の同期漏れや不整合が発生しやすい状態でした。
Zod の登場と Single Source of Truth
Zod は、TypeScript ファースト なスキーマバリデーションライブラリです。スキーマ定義から型を自動推論できるため、型定義とバリデーションの一元化を実現しました。
しかし、OpenAPI ドキュメントは依然として手動管理が必要でした。ここで zod-to-openapi
が登場し、Zod スキーマを OpenAPI 仕様に変換できるようになったのです。
以下の図は、zod-to-openapi
を活用した理想的なフローを示しています。
mermaidflowchart LR
zod["Zod スキーマ<br/>(Single Source)"] -->|自動推論| types["TypeScript 型"]
zod -->|ランタイム| validation["バリデーション"]
zod -->|zod-to-openapi| openapi["OpenAPI 仕様書"]
openapi -->|自動生成| swagger["Swagger UI"]
style zod fill:#b8e6b8
style types fill:#e1f5ff
style validation fill:#fff4e1
style openapi fill:#ffe1e1
style swagger fill:#f0e1ff
Zod スキーマを起点として、型・バリデーション・ドキュメントすべてを自動生成できる仕組みになります。
図で理解できる要点:
- Zod スキーマが唯一の情報源(Single Source of Truth)となる
- 型推論、バリデーション、OpenAPI 生成がすべて自動化される
- 手動同期が不要になり、不整合リスクがゼロになる
課題
従来の開発における 3 つの問題
API 開発において、以下のような課題が顕在化していました。
1. 重複したスキーマ定義
TypeScript の interface、Zod スキーマ、OpenAPI の schemas を、それぞれ別々に定義する必要がありました。
typescript// TypeScript の型定義
interface User {
id: string;
name: string;
email: string;
}
typescript// Zod スキーマ
const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
});
yaml# OpenAPI 定義(YAML)
components:
schemas:
User:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
format: email
required:
- id
- name
- email
上記のように、同じ内容を 3 回記述しなければならず、非効率でした。
2. 変更時の同期コスト
仕様変更が発生すると、3 箇所すべてを手動で修正する必要がありました。例えば、age
フィールドを追加する場合、以下の作業が必要です。
# | 修正箇所 | 作業内容 |
---|---|---|
1 | TypeScript 型 | interface に age: number を追加 |
2 | Zod スキーマ | age: z.number() を追加 |
3 | OpenAPI 仕様 | schemas に age プロパティを追加 |
4 | テストコード | age を含むテストデータを更新 |
このように、1 つの変更に対して複数ファイルの修正が必要で、修正漏れが発生しやすい状況でした。
3. ドキュメントの陳腐化
OpenAPI ドキュメントの更新を忘れると、実装とドキュメントが乖離してしまいます。
mermaidsequenceDiagram
participant Dev as 開発者
participant Code as 実装コード
participant Doc as API ドキュメント
participant User as API 利用者
Dev->>Code: age フィールド追加
Dev->>Doc: 更新を忘れる
Note over Doc: 古い仕様のまま
User->>Doc: 仕様を確認
User->>Code: API リクエスト<br/>(age なし)
Code-->>User: バリデーションエラー
Note over User: ドキュメントと<br/>実装が不一致
このような不整合により、API 利用者が混乱し、問い合わせ対応のコストが増加していました。
図で理解できる要点:
- ドキュメント更新漏れにより、利用者が誤った仕様でリクエストを送信
- バリデーションエラーが発生し、開発体験が悪化
- 手動同期に依存する限り、この問題は避けられない
解決策
zod-to-openapi
による一元管理
zod-to-openapi
を使用すると、Zod スキーマから OpenAPI 仕様を自動生成できます。これにより、以下のメリットが得られます。
# | メリット | 説明 |
---|---|---|
1 | Single Source of Truth | Zod スキーマのみを管理すればよい |
2 | 型安全性の向上 | TypeScript 型とバリデーションが自動で一致 |
3 | ドキュメントの常時最新化 | コード変更が即座にドキュメントへ反映 |
4 | 開発速度の向上 | 重複作業が削減され、本質的な開発に集中できる |
以下は、全体のアーキテクチャを示した図です。
mermaidflowchart TB
subgraph Source["情報源(Single Source)"]
zod["Zod スキーマ定義"]
end
subgraph Auto["自動生成物"]
types["TypeScript 型<br/>(z.infer)"]
validation["ランタイム<br/>バリデーション"]
openapi["OpenAPI 仕様<br/>(JSON)"]
end
subgraph Output["最終成果物"]
swagger["Swagger UI"]
client["型安全な<br/>API クライアント"]
end
zod -->|型推論| types
zod -->|parse/safeParse| validation
zod -->|zod-to-openapi| openapi
openapi --> swagger
types --> client
style Source fill:#b8e6b8
style Auto fill:#e1f5ff
style Output fill:#fff4e1
図で理解できる要点:
- Zod スキーマが唯一の定義元となり、すべてが自動生成される
- 開発者は Zod スキーマの管理のみに集中できる
- 型安全性とドキュメントの正確性が同時に保証される
インストールと基本設定
まずは必要なパッケージをインストールします。
bashyarn add zod @asteasolutions/zod-to-openapi
yarn add -D @types/node
次に、基本的な設定ファイルを作成しましょう。
typescript// src/openapi/registry.ts
import { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
// OpenAPI レジストリを作成
export const registry = new OpenAPIRegistry();
このレジストリに、後ほど Zod スキーマを登録していきます。
Zod スキーマの拡張
OpenAPI 仕様を生成するために、Zod スキーマに OpenAPI メタデータを追加します。
typescript// src/schemas/user.schema.ts
import { z } from 'zod';
import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
// Zod を OpenAPI 対応に拡張
extendZodWithOpenApi(z);
この初期化により、Zod スキーマに .openapi()
メソッドが追加されます。
typescript// ユーザースキーマの定義
export const UserSchema = z
.object({
id: z.string().openapi({
description: 'ユーザーの一意識別子',
example: 'user_123',
}),
name: z.string().min(1).max(100).openapi({
description: 'ユーザー名',
example: '山田太郎',
}),
email: z.string().email().openapi({
description: 'メールアドレス',
example: 'yamada@example.com',
}),
age: z
.number()
.int()
.min(0)
.max(150)
.optional()
.openapi({
description: '年齢(任意)',
example: 25,
}),
})
.openapi('User');
.openapi()
メソッドで、OpenAPI ドキュメントに表示される説明文やサンプル値を指定できます。
typescript// TypeScript 型を自動推論
export type User = z.infer<typeof UserSchema>;
// 推論される型:
// type User = {
// id: string;
// name: string;
// email: string;
// age?: number | undefined;
// }
この時点で、型定義とバリデーションが Zod スキーマから自動生成されています。
エンドポイントの登録
API エンドポイントを定義し、レジストリに登録します。
typescript// src/openapi/routes.ts
import { registry } from './registry';
import { UserSchema } from '../schemas/user.schema';
// GET /users/{id} エンドポイントの定義
registry.registerPath({
method: 'get',
path: '/users/{id}',
description: 'ユーザー情報を ID で取得します',
summary: 'ユーザー取得',
tags: ['Users'],
request: {
params: z.object({
id: z.string().openapi({
description: '取得するユーザーの ID',
example: 'user_123',
}),
}),
},
responses: {
200: {
description: 'ユーザー情報の取得に成功',
content: {
'application/json': {
schema: UserSchema,
},
},
},
404: {
description: 'ユーザーが見つかりません',
content: {
'application/json': {
schema: z.object({
error: z.string().openapi({
example: 'User not found',
}),
}),
},
},
},
},
});
上記のコードでは、パスパラメータ、レスポンススキーマ、エラーレスポンスをすべて Zod で定義しています。
typescript// POST /users エンドポイントの定義
registry.registerPath({
method: 'post',
path: '/users',
description: '新しいユーザーを作成します',
summary: 'ユーザー作成',
tags: ['Users'],
request: {
body: {
content: {
'application/json': {
schema: UserSchema.omit({ id: true }),
},
},
},
},
responses: {
201: {
description: 'ユーザーの作成に成功',
content: {
'application/json': {
schema: UserSchema,
},
},
},
400: {
description: 'バリデーションエラー',
content: {
'application/json': {
schema: z
.object({
error: z.string(),
details: z.array(z.string()),
})
.openapi({
example: {
error: 'Validation failed',
details: ['email: Invalid email format'],
},
}),
},
},
},
},
});
POST エンドポイントでは、UserSchema.omit({ id: true })
により、id を除いたスキーマをリクエストボディとして使用しています。
OpenAPI ドキュメントの生成
レジストリから OpenAPI 仕様を生成します。
typescript// src/openapi/generator.ts
import { OpenApiGeneratorV3 } from '@asteasolutions/zod-to-openapi';
import { registry } from './registry';
// OpenAPI ジェネレーターを作成
const generator = new OpenApiGeneratorV3(
registry.definitions
);
typescript// OpenAPI 仕様を生成
export const openApiDocument = generator.generateDocument({
openapi: '3.0.0',
info: {
version: '1.0.0',
title: 'User API',
description:
'Zod スキーマから自動生成された API ドキュメント',
},
servers: [
{
url: 'http://localhost:3000/api',
description: '開発環境',
},
{
url: 'https://api.example.com',
description: '本番環境',
},
],
});
この openApiDocument
オブジェクトが、完全な OpenAPI 3.0 仕様書となります。
typescript// ドキュメントをファイルに出力
import fs from 'fs';
import path from 'path';
const outputPath = path.join(
__dirname,
'../../openapi.json'
);
fs.writeFileSync(
outputPath,
JSON.stringify(openApiDocument, null, 2)
);
console.log(
`OpenAPI ドキュメントを生成しました: ${outputPath}`
);
これで、openapi.json
ファイルが自動生成されます。
具体例
実践的な API 実装例
ここでは、Next.js API Routes で zod-to-openapi
を活用した実装例を紹介します。
プロジェクト構成
plaintextsrc/
├── schemas/
│ ├── user.schema.ts # ユーザースキーマ
│ └── product.schema.ts # 商品スキーマ
├── openapi/
│ ├── registry.ts # レジストリ設定
│ ├── routes.ts # エンドポイント定義
│ └── generator.ts # ドキュメント生成
├── pages/
│ └── api/
│ ├── users/
│ │ ├── [id].ts # GET /api/users/:id
│ │ └── index.ts # POST /api/users
│ └── docs.ts # Swagger UI エンドポイント
└── utils/
└── validate.ts # バリデーションヘルパー
バリデーションヘルパーの作成
API ハンドラーで使い回せるバリデーションヘルパーを作成します。
typescript// src/utils/validate.ts
import { z } from 'zod';
import { NextApiRequest, NextApiResponse } from 'next';
export function validateRequest<T extends z.ZodTypeAny>(
schema: T,
data: unknown
): z.infer<T> {
const result = schema.safeParse(data);
if (!result.success) {
throw new ValidationError(result.error);
}
return result.data;
}
typescript// カスタムエラークラス
export class ValidationError extends Error {
constructor(public zodError: z.ZodError) {
super('Validation failed');
this.name = 'ValidationError';
}
toJSON() {
return {
error: this.message,
details: this.zodError.errors.map((err) => ({
path: err.path.join('.'),
message: err.message,
})),
};
}
}
このヘルパーにより、バリデーションエラーを統一的に処理できます。
API ハンドラーの実装
Zod スキーマを使った型安全な API ハンドラーを実装します。
typescript// src/pages/api/users/index.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { UserSchema } from '../../../schemas/user.schema';
import { validateRequest, ValidationError } from '../../../utils/validate';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
// リクエストボディをバリデーション
const userData = validateRequest(
UserSchema.omit({ id: true }),
req.body
);
typescript // ユーザー作成処理(ダミー実装)
const newUser = {
id: `user_${Date.now()}`,
...userData,
};
// レスポンスもスキーマで検証
const validatedUser = validateRequest(UserSchema, newUser);
return res.status(201).json(validatedUser);
} catch (error) {
typescript // バリデーションエラーのハンドリング
if (error instanceof ValidationError) {
return res.status(400).json(error.toJSON());
}
// その他のエラー
console.error('Unexpected error:', error);
return res.status(500).json({
error: 'Internal server error',
});
}
}
このように、リクエストとレスポンスの両方で型安全性を確保できます。
typescript// src/pages/api/users/[id].ts
import { NextApiRequest, NextApiResponse } from 'next';
import { UserSchema } from '../../../schemas/user.schema';
import { z } from 'zod';
import { validateRequest } from '../../../utils/validate';
// パスパラメータのスキーマ
const ParamsSchema = z.object({
id: z.string(),
});
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== 'GET') {
return res.status(405).json({ error: 'Method not allowed' });
}
typescript try {
// パスパラメータをバリデーション
const { id } = validateRequest(ParamsSchema, req.query);
// ユーザー取得処理(ダミー実装)
const user = {
id,
name: '山田太郎',
email: 'yamada@example.com',
age: 25,
};
// レスポンスをバリデーション
const validatedUser = validateRequest(UserSchema, user);
return res.status(200).json(validatedUser);
} catch (error) {
typescript if (error instanceof ValidationError) {
return res.status(400).json(error.toJSON());
}
return res.status(500).json({
error: 'Internal server error',
});
}
}
Swagger UI の組み込み
生成した OpenAPI ドキュメントを Swagger UI で表示します。
typescript// src/pages/api/docs.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { openApiDocument } from '../../openapi/generator';
export default function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// OpenAPI JSON を返す
res.status(200).json(openApiDocument);
}
次に、Swagger UI をセットアップします。
bashyarn add swagger-ui-react
yarn add -D @types/swagger-ui-react
typescript// src/pages/api-docs.tsx
import dynamic from 'next/dynamic';
import 'swagger-ui-react/swagger-ui.css';
// SSR を無効化して Swagger UI を読み込む
const SwaggerUI = dynamic(
() => import('swagger-ui-react'),
{
ssr: false,
}
);
export default function ApiDocs() {
return (
<div>
<SwaggerUI url='/api/docs' />
</div>
);
}
これで、http://localhost:3000/api-docs
にアクセスすると、自動生成された API ドキュメントが表示されます。
以下の図は、リクエストからレスポンスまでのフローを示しています。
mermaidsequenceDiagram
participant Client as API クライアント
participant Handler as API ハンドラー
participant Validator as validateRequest
participant Schema as Zod スキーマ
participant DB as データベース
Client->>Handler: POST /api/users<br/>{ name, email, age }
Handler->>Validator: リクエストボディ検証
Validator->>Schema: UserSchema.safeParse()
alt バリデーション成功
Schema-->>Validator: 検証済みデータ
Validator-->>Handler: 型安全なデータ
Handler->>DB: ユーザー作成
DB-->>Handler: 作成されたユーザー
Handler->>Validator: レスポンス検証
Validator->>Schema: UserSchema.safeParse()
Schema-->>Validator: 検証済みデータ
Validator-->>Handler: 型安全なレスポンス
Handler-->>Client: 201 Created<br/>{ id, name, email, age }
else バリデーション失敗
Schema-->>Validator: ZodError
Validator-->>Handler: ValidationError
Handler-->>Client: 400 Bad Request<br/>{ error, details }
end
図で理解できる要点:
- リクエストとレスポンスの両方でバリデーションを実施
- バリデーション失敗時は統一されたエラー形式で返却
- Zod スキーマが型安全性とランタイム安全性を同時に保証
複雑なスキーマの例
実務でよく使う、ネストしたスキーマや共通スキーマの定義例を紹介します。
typescript// src/schemas/common.schema.ts
import { z } from 'zod';
import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
extendZodWithOpenApi(z);
// ページネーション用の共通スキーマ
export const PaginationSchema = z
.object({
page: z.number().int().min(1).default(1).openapi({
description: 'ページ番号',
example: 1,
}),
limit: z
.number()
.int()
.min(1)
.max(100)
.default(20)
.openapi({
description: '1 ページあたりの件数',
example: 20,
}),
total: z.number().int().min(0).openapi({
description: '全件数',
example: 100,
}),
})
.openapi('Pagination');
typescript// src/schemas/product.schema.ts
import { z } from 'zod';
import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
extendZodWithOpenApi(z);
// カテゴリスキーマ
export const CategorySchema = z
.object({
id: z.string().openapi({
description: 'カテゴリ ID',
example: 'cat_123',
}),
name: z.string().openapi({
description: 'カテゴリ名',
example: '電化製品',
}),
})
.openapi('Category');
typescript// 商品スキーマ(ネスト構造)
export const ProductSchema = z
.object({
id: z.string().openapi({
description: '商品 ID',
example: 'prod_456',
}),
name: z.string().min(1).max(200).openapi({
description: '商品名',
example: 'ワイヤレスイヤホン',
}),
price: z.number().min(0).openapi({
description: '価格(円)',
example: 9800,
}),
category: CategorySchema.openapi({
description: '商品カテゴリ',
}),
tags: z.array(z.string()).openapi({
description: 'タグ一覧',
example: [
'Bluetooth',
'防水',
'ノイズキャンセリング',
],
}),
inStock: z.boolean().openapi({
description: '在庫あり',
example: true,
}),
})
.openapi('Product');
typescript// ページネーション付き商品リストのレスポンススキーマ
export const ProductListResponseSchema = z
.object({
data: z.array(ProductSchema).openapi({
description: '商品一覧',
}),
pagination: PaginationSchema.openapi({
description: 'ページネーション情報',
}),
})
.openapi('ProductListResponse');
このように、スキーマを組み合わせることで、複雑な API レスポンスも型安全に定義できます。
typescript// src/openapi/routes.ts(商品エンドポイント追加)
import { registry } from './registry';
import {
ProductSchema,
ProductListResponseSchema,
} from '../schemas/product.schema';
registry.registerPath({
method: 'get',
path: '/products',
description: '商品一覧を取得します',
summary: '商品一覧取得',
tags: ['Products'],
request: {
query: z.object({
page: z
.string()
.regex(/^\d+$/)
.transform(Number)
.optional(),
limit: z
.string()
.regex(/^\d+$/)
.transform(Number)
.optional(),
category: z.string().optional().openapi({
description: 'カテゴリ ID でフィルタリング',
example: 'cat_123',
}),
}),
},
responses: {
200: {
description: '商品一覧の取得に成功',
content: {
'application/json': {
schema: ProductListResponseSchema,
},
},
},
},
});
クエリパラメータの型変換(transform
)も含め、すべて Zod で定義しています。
CI/CD への組み込み
OpenAPI ドキュメントの自動生成をビルドプロセスに組み込む例です。
json// package.json
{
"scripts": {
"dev": "next dev",
"build": "yarn generate:openapi && next build",
"generate:openapi": "ts-node src/openapi/generator.ts",
"lint:openapi": "yarn generate:openapi && openapi-validator openapi.json"
}
}
typescript// src/openapi/generator.ts(改良版)
import fs from 'fs';
import path from 'path';
import { OpenApiGeneratorV3 } from '@asteasolutions/zod-to-openapi';
import { registry } from './registry';
import './routes'; // ルート定義を読み込む
const generator = new OpenApiGeneratorV3(
registry.definitions
);
const openApiDocument = generator.generateDocument({
openapi: '3.0.0',
info: {
version: process.env.npm_package_version || '1.0.0',
title: 'User API',
description:
'Zod スキーマから自動生成された API ドキュメント',
},
servers: [
{
url: 'http://localhost:3000/api',
description: '開発環境',
},
{
url: 'https://api.example.com',
description: '本番環境',
},
],
});
typescript// ファイル出力
const outputPath = path.join(process.cwd(), 'openapi.json');
fs.writeFileSync(
outputPath,
JSON.stringify(openApiDocument, null, 2),
'utf-8'
);
console.log(
`✅ OpenAPI ドキュメントを生成しました: ${outputPath}`
);
yaml# .github/workflows/openapi.yml
name: OpenAPI Validation
on:
pull_request:
paths:
- 'src/schemas/**'
- 'src/openapi/**'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Generate OpenAPI document
run: yarn generate:openapi
- name: Validate OpenAPI schema
run: yarn lint:openapi
- name: Upload OpenAPI artifact
uses: actions/upload-artifact@v3
with:
name: openapi-spec
path: openapi.json
このワークフローにより、スキーマ変更時に自動で OpenAPI 仕様書が生成・検証されます。
まとめ
zod-to-openapi
を活用することで、Zod スキーマから OpenAPI ドキュメントを自動生成でき、以下のメリットが得られます。
# | メリット | 効果 |
---|---|---|
1 | Single Source of Truth | Zod スキーマのみの管理で、型・バリデーション・ドキュメントすべてが自動生成される |
2 | 型安全性の向上 | TypeScript の型推論により、コンパイル時に型エラーを検出できる |
3 | ドキュメントの常時最新化 | コード変更が即座にドキュメントへ反映され、不整合が発生しない |
4 | 開発速度の向上 | 重複作業が削減され、本質的な機能開発に集中できる |
5 | バリデーションの統一 | リクエスト・レスポンス両方で同じスキーマを使い、一貫性が保たれる |
従来の開発では、型定義・バリデーション・ドキュメントを別々に管理する必要があり、変更時の同期コストが課題でした。zod-to-openapi
により、この問題が根本的に解決されます。
特に、チーム開発や API の公開を行うプロジェクトでは、正確なドキュメントが開発体験を大きく左右します。Zod スキーマを起点とした自動生成により、常に最新のドキュメントを提供でき、API 利用者との信頼関係を構築できるでしょう。
ぜひ、次のプロジェクトで zod-to-openapi
を導入してみてください。きっと、開発効率の向上を実感していただけるはずです。
関連リンク
- article
Zod × OpenAPI:`zod-to-openapi` で契約からドキュメントを自動生成
- article
Zod で CSV/TSV インポートを安全に処理:パース → 検証 → 差分レポート
- article
Zod のブランド型(Branding)設計:メール・ULID・金額などの値オブジェクト化
- article
Zod クイックリファレンス:`string/number/boolean/date/enum/literal` 速見表
- article
Zod 導入最短ルート:yarn/pnpm/bun でのセットアップと型サポート
- article
Zod 全体像を図解で理解:プリミティブ → 合成 → 効果(transform/coerce/refine)の流れ
- article
Next.js の RSC 境界設計:Client Components を最小化する責務分離戦略
- article
Mermaid 矢印・接続子チートシート:線種・方向・注釈の一覧早見
- article
Codex とは何か?AI コーディングの基礎・仕組み・適用範囲をやさしく解説
- article
MCP サーバー 設計ベストプラクティス:ツール定義、権限分離、スキーマ設計の要点まとめ
- article
Astro で動的 OG 画像を生成する:Satori/Canvas 連携の実装レシピ
- article
Lodash で管理画面テーブルを強化:並び替え・フィルタ・ページングの骨格
- blog
iPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
- blog
Googleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
- blog
【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
- blog
Googleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
- blog
Pixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
- blog
フロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来