目次
現代の API 開発において、**OpenAPI 仕様(旧 Swagger 仕様)**は事実上の標準となっている。API の設計、ドキュメント作成、クライアント/サーバーコードの生成、テスト自動化——これらを一貫して行うための強力なツールだ。本記事では、OpenAPI 仕様の基本概念から、実用的な定義の書き方、ドキュメント自動化、コード生成、API ファースト開発のプラクティスまでを体系的に解説する。
OpenAPI 仕様とは
**OpenAPI 仕様(OpenAPI Specification, OAS)**は、RESTful API の構造を機械可読な形式で記述するための標準仕様だ。
【OpenAPI 仕様のメリット】
1. 単一の信頼できる情報源(Single Source of Truth)
- API 設計、ドキュメント、実装が一貫
- 仕様と実装の乖離を防止
2. 自動ドキュメント生成
- 人間が読むためのインタラクティブな docs
- 常に最新の状態を維持
3. コード生成
- クライアント SDK(TypeScript, Python, Java など)
- サーバーサイドのスタブコード
- モックサーバー
4. ツールエコシステム
- Swagger UI、Redoc、Stoplight
- Postman、Insomnia でのインポート
- 自動テスト生成
歴史とバージョン
【OpenAPI 仕様の歴史】
2010 年:Swagger 仕様 1.0(Wordnik が開発)
2014 年:Swagger 2.0(大幅な改善)
2015 年:SmartBear Software が Swagger 仕様をオープンソース化
2015 年:Linux Foundation 傘下の OpenAPI Initiative 発足
2016 年:OpenAPI 3.0 公開(Swagger から OpenAPI へ改名)
2021 年:OpenAPI 3.1 公開(JSON Schema 2020-12 に完全準拠)
【バージョン比較】
| 機能 | Swagger 2.0 | OpenAPI 3.0 | OpenAPI 3.1 |
|------|------------|-------------|-------------|
| **JSON Schema** | 一部準拠 | 一部準拠 | 完全準拠 |
| **コンポーネント** | definitions | components | components |
| **サーバー定義** | host + basePath | servers(URL 配列) | servers(変数対応) |
| **リクエストボディ** | 1 つのみ | 複数(media type 別) | 複数 |
| **Webhooks** | 非対応 | 非対応 | 対応 |
| **null 型** | x-nullable | nullable: true | type: "null" |
OpenAPI ドキュメントの基本構造
OpenAPI ドキュメントは YAML または JSON 形式で記述する。YAML の方が可読性が高く一般的だ。
最小限の構造
openapi: "3.1.0"
info:
title: "サンプル API"
version: "1.0.0"
description: "これはサンプル API のドキュメントです"
paths:
/users:
get:
summary: "ユーザー一覧を取得"
responses:
"200":
description: "成功"
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/User"
components:
schemas:
User:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: "山田太郎"
email:
type: string
format: email
example: "taro@example.com"
主要セクション
【OpenAPI ドキュメントの構成要素】
openapi: "3.1.0" # 使用する OpenAPI 仕様のバージョン
info: # API のメタ情報
title: "API 名"
version: "1.0.0"
description: "説明"
contact: # 連絡先
name: "サポートチーム"
email: "support@example.com"
license: # ライセンス
name: "MIT"
url: "https://opensource.org/licenses/MIT"
servers: # サーバーエンドポイント
- url: "https://api.example.com/v1"
description: "本番環境"
- url: "https://staging-api.example.com/v1"
description: "ステージング環境"
paths: # エンドポイント定義
/users:
get: ...
post: ...
/users/{id}:
get: ...
put: ...
delete: ...
components: # 再利用可能なコンポーネント
schemas: # データモデル
responses: # レスポンス定義
parameters: # パラメータ定義
requestBodies: # リクエストボディ定義
headers: # ヘッダー定義
securitySchemes: # 認証スキーム
security: # 全局セキュリティ設定
tags: # 操作のグルーピング用タグ
externalDocs: # 外部ドキュメントへのリンク
パスの定義——エンドポイントの設計
HTTP メソッドと操作
paths:
/users:
# コレクション操作
get:
tags: ["users"]
summary: "ユーザー一覧を取得"
description: " pagination をサポート"
operationId: "listUsers"
parameters:
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
- name: offset
in: query
schema:
type: integer
default: 0
responses:
"200":
description: "成功"
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: "#/components/schemas/User"
total:
type: integer
example: 100
limit:
type: integer
offset:
type: integer
post:
tags: ["users"]
summary: "ユーザーを作成"
operationId: "createUser"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateUserRequest"
responses:
"201":
description: "作成成功"
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"400":
description: "バリデーションエラー"
content:
application/json:
schema:
$ref: "#/components/responses/BadRequest"
/users/{id}:
# 単一リソース操作
get:
tags: ["users"]
summary: "ユーザーを取得"
operationId: "getUserById"
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
"200":
description: "成功"
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"404":
description: "ユーザーが見つからない"
put:
tags: ["users"]
summary: "ユーザーを更新(全体)"
operationId: "replaceUser"
parameters:
- name: id
in: path
required: true
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateUserRequest"
responses:
"200":
description: "更新成功"
patch:
tags: ["users"]
summary: "ユーザーを部分更新"
operationId: "updateUser"
parameters:
- name: id
in: path
required: true
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PartialUpdateUserRequest"
responses:
"200":
description: "部分更新成功"
delete:
tags: ["users"]
summary: "ユーザーを削除"
operationId: "deleteUser"
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
"204":
description: "削除成功(ボディなし)"
パスパラメータの書式
paths:
# シンプルな ID
/users/{id}:
parameters:
- name: id
in: path
required: true
schema:
type: integer
# 複合キー
/organizations/{orgId}/users/{userId}:
parameters:
- name: orgId
in: path
required: true
schema:
type: string
format: uuid
- name: userId
in: path
required: true
schema:
type: string
format: uuid
# パスパターン(OpenAPI 3.1)
/files/{path}:
parameters:
- name: path
in: path
required: true
schema:
type: string
style: simple
explode: false
スキーマ定義——データモデルの設計
基本型の定義
components:
schemas:
# 基本型の直接使用
UserId:
type: integer
minimum: 1
example: 1
Email:
type: string
format: email
example: "user@example.com"
Timestamp:
type: string
format: date-time
example: "2025-08-15T10:30:00Z"
# オブジェクト型
User:
type: object
description: "ユーザー情報"
required:
- id
- email
- created_at
properties:
id:
type: integer
description: "ユーザー ID"
example: 1
readOnly: true
email:
type: string
format: email
description: "メールアドレス(ログインに使用)"
example: "taro@example.com"
name:
type: string
description: "表示名"
example: "山田太郎"
minLength: 1
maxLength: 50
role:
type: string
description: "ロール"
enum:
- admin
- editor
- viewer
default: "viewer"
profile:
$ref: "#/components/schemas/UserProfile"
created_at:
type: string
format: date-time
readOnly: true
updated_at:
type: string
format: date-time
readOnly: true
UserProfile:
type: object
properties:
bio:
type: string
maxLength: 500
example: "エンジニアとして働いています"
avatar_url:
type: string
format: uri
nullable: true
social_links:
type: object
properties:
twitter:
type: string
format: uri
github:
type: string
format: uri
linkedin:
type: string
format: uri
配列と組み合わせ
components:
schemas:
# 配列
UserList:
type: object
properties:
data:
type: array
items:
$ref: "#/components/schemas/User"
pagination:
$ref: "#/components/schemas/PaginationInfo"
PaginationInfo:
type: object
properties:
total:
type: integer
example: 100
limit:
type: integer
example: 20
offset:
type: integer
example: 0
has_more:
type: boolean
example: true
# 組み合わせ(allOf, anyOf, oneOf)
# allOf: すべての条件を満たす(継承パターン)
DetailedUser:
allOf:
- $ref: "#/components/schemas/User"
- type: object
properties:
department:
type: string
example: "エンジニアリング部"
manager_id:
type: integer
nullable: true
# anyOf: いずれか一つ以上を満たす
SearchTarget:
anyOf:
- $ref: "#/components/schemas/User"
- $ref: "#/components/schemas/Team"
- $ref: "#/components/schemas/Project"
# oneOf: ちょうど一つを満たす(排他的)
PaymentMethod:
oneOf:
- $ref: "#/components/schemas/CreditCardPayment"
- $ref: "#/components/schemas/BankTransferPayment"
- $ref: "#/components/schemas/CryptoPayment"
discriminator:
propertyName: "type"
mapping:
credit_card: "#/components/schemas/CreditCardPayment"
bank_transfer: "#/components/schemas/BankTransferPayment"
crypto: "#/components/schemas/CryptoPayment"
列挙型と定数
components:
schemas:
# 列挙型
UserRole:
type: string
enum:
- admin
- editor
- viewer
x-enum-varnames:
- ADMIN
- EDITOR
- VIEWER
UserStatus:
type: string
enum:
- active
- inactive
- suspended
- deleted
# 定数
ApiVersion:
type: string
const: "v1"
# 数値の列挙
HttpStatusCode:
type: integer
enum:
- 200
- 201
- 204
- 400
- 401
- 403
- 404
- 500
レスポンスの定義
ステータスコード別レスポンス
paths:
/users/{id}:
get:
summary: "ユーザーを取得"
responses:
# 成功
"200":
description: "成功"
headers:
X-RateLimit-Limit:
schema:
type: integer
description: "1 時間のリクエスト上限"
X-RateLimit-Remaining:
schema:
type: integer
description: "残リクエスト数"
content:
application/json:
schema:
$ref: "#/components/schemas/User"
# クライアントエラー
"400":
description: "不正なリクエスト"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error:
code: "INVALID_REQUEST"
message: "リクエストパラメータが不正です"
details:
- field: "id"
message: "整数値を指定してください"
"401":
description: "認証が必要"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error:
code: "UNAUTHORIZED"
message: "認証トークンが無効です"
"403":
description: "アクセス権限がありません"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error:
code: "FORBIDDEN"
message: "このリソースへのアクセス権限がありません"
"404":
description: "リソースが見つかりません"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error:
code: "NOT_FOUND"
message: "ユーザーが見つかりません"
"429":
description: "レート制限超過"
headers:
Retry-After:
schema:
type: integer
description: "再試行可能なまでの秒数"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
# サーバーエラー
"500":
description: "内部サーバーエラー"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
description: "サービス利用不可"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
エラーレスポンスの共通化
components:
schemas:
Error:
type: object
required:
- error
properties:
error:
type: object
required:
- code
- message
properties:
code:
type: string
description: "エラーコード(プログラムで処理可能)"
example: "VALIDATION_ERROR"
message:
type: string
description: "人間向けのエラーメッセージ"
example: "入力値の検証に失敗しました"
details:
type: array
description: "エラー詳細(バリデーションエラー等)"
items:
type: object
properties:
field:
type: string
description: "問題のあるフィールド"
message:
type: string
description: "フィールド固有のエラーメッセージ"
code:
type: string
description: "フィールド固有のエラーコード"
trace_id:
type: string
description: "ログ追跡用の ID"
example: "req_abc123xyz"
responses:
BadRequest:
description: "不正なリクエスト"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
Unauthorized:
description: "認証が必要"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
Forbidden:
description: "アクセス権限がありません"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
NotFound:
description: "リソースが見つかりません"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
InternalServerError:
description: "内部サーバーエラー"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
認証の定義
セキュリティスキーム
components:
securitySchemes:
# Bearer トークン(JWT など)
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: "JWT アクセストークン"
# API キー(ヘッダー)
apiKeyHeader:
type: apiKey
in: header
name: X-API-Key
description: "ヘッダーで API キーを送信"
# API キー(クエリパラメータ)
apiKeyQuery:
type: apiKey
in: query
name: api_key
description: "クエリパラメータで API キーを送信"
# OAuth 2.0
oauth2:
type: oauth2
description: "OAuth 2.0 認証"
flows:
authorizationCode:
authorizationUrl: "https://auth.example.com/oauth2/authorize"
tokenUrl: "https://auth.example.com/oauth2/token"
refreshUrl: "https://auth.example.com/oauth2/refresh"
scopes:
read: "読み取り専用アクセス"
write: "書き込みアクセス"
admin: "管理者アクセス"
clientCredentials:
tokenUrl: "https://auth.example.com/oauth2/token"
scopes:
read: "読み取り専用アクセス"
write: "書き込みアクセス"
implicit:
authorizationUrl: "https://auth.example.com/oauth2/authorize"
scopes:
read: "読み取り専用アクセス"
password:
tokenUrl: "https://auth.example.com/oauth2/token"
scopes:
read: "読み取り専用アクセス"
write: "書き込みアクセス"
# Basic 認証
basicAuth:
type: http
scheme: basic
description: "HTTP Basic 認証"
# 全局セキュリティ(デフォルト)
security:
- bearerAuth: []
# またはパスごとにセキュリティをオーバーライド
paths:
/public/health:
get:
summary: "ヘルスチェック(認証不要)"
security: [] # 認証不要
responses:
"200":
description: "正常"
/users:
get:
summary: "ユーザー一覧(読み取りスコープ必要)"
security:
- oauth2:
- read
- bearerAuth: []
responses:
"200":
description: "成功"
post:
summary: "ユーザー作成(書き込みスコープ必要)"
security:
- oauth2:
- write
- bearerAuth: []
responses:
"201":
description: "作成成功"
コード生成——自動実装の活用
OpenAPI Generator
OpenAPI Generatorは、OpenAPI 仕様から様々な言語のコードを生成するツールだ。
# CLI インストール
npm install -g @openapitools/openapi-generator-cli
# クライアント SDK 生成(TypeScript)
openapi-generator generate \
-i openapi.yaml \
-g typescript-axios \
-o ./generated-client \
--additional-properties=supportsES6=true,npmName=my-api-client,npmVersion=1.0.0
# サーバーサイドスタブ生成(Node.js/Express)
openapi-generator generate \
-i openapi.yaml \
-g nodejs-express-server \
-o ./generated-server
# Python クライアント
openapi-generator generate \
-i openapi.yaml \
-g python \
-o ./generated-python-client \
--additional-properties=packageName=my_api_client
# Java(Spring Boot)
openapi-generator generate \
-i openapi.yaml \
-g spring \
-o ./generated-java-server \
--additional-properties=interfaceOnly=true
Swagger Codegen
# Swagger Codegen CLI
java -jar swagger-codegen-cli.jar generate \
-i openapi.yaml \
-l typescript-angular \
-o ./generated-client
生成されるコードの例(TypeScript)
// 自動生成された API クライアント
import { Configuration, UsersApi } from './generated-client';
const config = new Configuration({
basePath: 'https://api.example.com/v1',
accessToken: 'your-jwt-token'
});
const usersApi = new UsersApi(config);
// 型安全な API コール
async function fetchUsers() {
const response = await usersApi.listUsers(20, 0);
// response.data: UserList
console.log(response.data.data);
console.log(response.data.pagination.total);
}
async function createUser(email: string, name: string) {
const response = await usersApi.createUser({
email,
name
});
// response.data: User
console.log(`Created user ${response.data.id}`);
}
ドキュメント自動化——Swagger UI と Redoc
Swagger UI
Swagger UIは、OpenAPI 仕様からインタラクティブな API ドキュメントを生成する。
# docker-compose.yml
version: '3.8'
services:
swagger-ui:
image: swaggerapi/swagger-ui:latest
ports:
- "8080:8080"
volumes:
- ./openapi.yaml:/usr/share/nginx/html/openapi.yaml
environment:
SWAGGER_JSON: /usr/share/nginx/html/openapi.yaml
アクセス:http://localhost:8080/?url=openapi.yaml
Redoc
Redocは、よりモダンで読みやすいドキュメントを生成する。
<!DOCTYPE html>
<html>
<head>
<title>API Documentation</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
<style>
body { margin: 0; padding: 0; }
</style>
</head>
<body>
<redoc spec-url="openapi.yaml"></redoc>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"></script>
</body>
</html>
Stoplight Elements
Stoplight Elementsは、3 カラムレイアウトのモダンなドキュメントを生成する。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>API Documentation</title>
<link rel="stylesheet" href="https://unpkg.com/elements-gui/dist/elements.min.css">
</head>
<body>
<elements-api
apiDescriptionUrl="openapi.yaml"
router="hash"
layout="sidebar"
></elements-api>
<script src="https://unpkg.com/elements-gui/dist/elements.min.js"></script>
</body>
</html>
API ファースト開発
API ファーストは、実装よりも先に API 設計(OpenAPI 仕様)を作成するアプローチだ。
【API ファースト開発のフロー】
1. 要件定義
↓
2. API 設計(OpenAPI 仕様)
↓
3. レビュー・承認
↓
4. コード生成(スタブ・クライアント)
↓
5. 実装
↓
6. テスト
↓
7. ドキュメント公開
モックサーバー
実装前にモックサーバーを使って早期にクライアント開発を始められる。
# Prism(Stoplight)を使ったモックサーバー
npm install -g @stoplight/prism-cli
# モックサーバー起動
prism mock openapi.yaml
# 自動生成されたエンドポイントにリクエスト
curl http://localhost:4010/users
# → スキーマに基づくモックレスポンスが返る
バリデーション
# リクエスト/レスポンスのバリデーション
prism proxy openapi.yaml https://backend.example.com
# 実際のレスポンスが仕様を満たしているか検証
curl http://localhost:4010/users
CI/CD への統合
# .github/workflows/api-validation.yml
name: API Validation
on:
push:
paths:
- 'openapi.yaml'
pull_request:
paths:
- 'openapi.yaml'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate OpenAPI
uses: swaggerexpert/swagger-editor-validate@v1
with:
definition-file: openapi.yaml
- name: Lint OpenAPI
run: |
npm install -g @redocly/cli
redocly lint openapi.yaml
- name: Generate Client
run: |
openapi-generator generate \
-i openapi.yaml \
-g typescript-axios \
-o ./generated-client \
--additional-properties=supportsES6=true
- name: Generate Docs
run: |
npx @redocly/cli build-docs openapi.yaml -o ./docs/index.html
- name: Upload Docs
uses: actions/upload-pages-artifact@v3
with:
path: ./docs
バージョニング戦略
URL パスによるバージョニング
servers:
- url: "https://api.example.com/v1"
description: "API v1"
- url: "https://api.example.com/v2"
description: "API v2"
# v1 と v2 の仕様を別ファイルで管理
# openapi.v1.yaml
# openapi.v2.yaml
バージョン移行のガイド
info:
title: "Example API"
version: "2.0.0"
description: |
## バージョン移行ガイド
### v1.0 → v2.0 の変更点
#### 削除されたエンドポイント
- `GET /users/search` → `GET /users` に統合(query パラメータ使用)
#### 変更されたレスポンス形式
```json
// v1.0
{ "users": [...], "count": 10 }
// v2.0
{
"data": [...],
"pagination": {
"total": 10,
"limit": 20,
"offset": 0
}
}
```
#### 新しく必須になったパラメータ
- `POST /users` で `email` が必須に
#### 非推奨(deprecation)
- `X-API-Key` ヘッダー → Bearer トークンへ移行(2025-12-31 まで)
下位互換性の維持
paths:
/users:
get:
summary: "ユーザー一覧を取得"
deprecated: false
parameters:
# 旧パラメータ(非推奨)
- name: count
in: query
deprecated: true
schema:
type: integer
default: 20
description: "非推奨:代わりに limit を使用してください"
# 新パラメータ
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
"200":
description: "成功"
content:
application/json:
schema:
oneOf:
# v1 形式(下位互換)
- $ref: "#/components/schemas/UserListV1"
# v2 形式(新規推奨)
- $ref: "#/components/schemas/UserListV2"
ベストプラクティス
命名規則
# リソース名は複数形
paths:
/users: {} # ✅ 良い
/user: {} # ❌ 避ける
# スネークケースまたはケバブケース
components:
schemas:
User: {} # スキーマ名はパスカルケース
UserProfile: {}
CreateUserRequest: {}
# HTTP メソッドの意味を正しく使う
paths:
/users:
get: {} # 取得(一覧)
post: {} # 作成
/users/{id}:
get: {} # 取得(単一)
put: {} # 置換(全体更新)
patch: {} # 部分更新
delete: {} # 削除
エラーハンドリング
# 一貫したエラーレスポンス形式
components:
schemas:
Error:
type: object
properties:
error:
type: object
properties:
code:
type: string # プログラムで処理可能なエラーコード
message:
type: string # 人間向けのメッセージ
details: # 追加情報(任意)
type: array
items:
type: object
# 適切なステータスコードを使用
responses:
"400": # バリデーションエラー
"401": # 認証エラー
"403": # 権限エラー
"404": # NotFound
"409": # 競合(重複等)
"422": # 意味論的エラー(バリデーション)
"429": # レート制限
"500": # サーバーエラー
"503": # サービス利用不可
ページネーション
paths:
/users:
get:
parameters:
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
- name: offset
in: query
schema:
type: integer
default: 0
- name: sort
in: query
schema:
type: string
enum:
- created_at
- name
- email
default: "created_at"
- name: order
in: query
schema:
type: string
enum:
- asc
- desc
default: "desc"
responses:
"200":
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: "#/components/schemas/User"
pagination:
type: object
properties:
total:
type: integer
limit:
type: integer
offset:
type: integer
has_more:
type: boolean
まとめ
OpenAPI 仕様は、現代の API 開発において不可欠なツールだ。
- 単一の信頼できる情報源: 仕様、ドキュメント、実装の一貫性を保つ
- 自動ドキュメント生成: Swagger UI、Redoc でインタラクティブな docs
- コード生成: クライアント SDK、サーバーサイドスタブ、モックサーバー
- API ファースト開発: 設計先行で品質向上、早期クライアント開発
- エコシステム: 豊富なツール、CI/CD 統合、バリデーション
適切に設計された OpenAPI 仕様は、開発者の生産性を高め、API の品質を向上させ、ドキュメントのメンテナンスコストを削減する。
参考資料
- OpenAPI Specification 3.1.0: https://spec.openapis.org/oas/v3.1.0
- Swagger UI: https://swagger.io/tools/swagger-ui/
- Redoc: https://redoc.ly/
- OpenAPI Generator: https://openapi-generator.tech/
- Stoplight Prism: https://stoplight.io/open-source/prism
- Redocly CLI: https://redocly.com/docs/cli/
- API Style Guide: https://apistylebook.stoplight.io/
免責事項 — 掲載情報は執筆時点のものです。料金・機能は変更される場合があります。最新情報は各公式サイトをご確認ください。