2026年7月13日

2026年7月13日

PHPのswagger-phpでAPIドキュメントを自動生成する方法|OpenAPIの書き方とSwagger UIでの公開

PHPで作ったAPIのドキュメントは、swagger-php を使うとコードに書いた属性(アトリビュート)からOpenAPI形式のファイルを自動生成できます。流れは「Composerで入れる」「コントローラーやモデルに #[OA\...] の属性を書く」「vendor/bin/openapi で openapi.yaml を出力する」「Swagger UIで表示する」の4段階です。この記事では、最小構成のサンプル、パラメーターやスキーマの書き方、生成時によく出るエラー、CIでドキュメントを最新に保つ方法までを説明します。

SwaggerとOpenAPIの関係

最初に名前を整理しておきます。APIの仕様を記述する形式は、もともと「Swagger」と呼ばれていましたが、バージョン3.0からは「OpenAPI Specification(OAS)」という名前になりました。現在「Swagger」は、OpenAPIのファイルを表示・編集するツール群(Swagger UI、Swagger Editorなど)の名前として使われています。

つまり、作るのは OpenAPI形式のファイル(YAMLまたはJSON) で、それを見やすく表示するのが Swagger UI です。PHPの swagger-php は、このOpenAPIファイルをPHPのコードから生成するライブラリです。OpenAPIには3.0系と3.1系などの版があり、swagger-phpは既定で3.0系を出力し、オプションで3.1系も指定できます(2026年10月現在)。対応する版や既定値はswagger-phpのバージョンで変わるため、公式ドキュメントで確認してください。

コードから生成するメリット

OpenAPIファイルを手で書く方法もありますが、APIの実装を変えたときにドキュメントの更新を忘れがちです。swagger-phpでは、エンドポイントを処理するメソッドのすぐ上に仕様を書くため、実装とドキュメントが同じ場所にあり、ずれに気づきやすくなります。生成したファイルは、Swagger UIでの表示のほか、クライアントコードの生成やテストツールの入力としても使えます。

インストール

PHP 8.1以降なら、属性(アトリビュート)を使う書き方を選ぶのがおすすめです。以前はPHPDocコメントの中に @OA\Get(...) と書くアノテーション形式が主流でしたが、こちらは追加のライブラリ(doctrine/annotations)が必要で、新しく書くなら属性のほうが扱いやすくなっています。

composer require zircote/swagger-php

swagger-phpはクラスを読み込んで属性を解析するため、対象のクラスがComposerのオートロードで読み込める状態になっている必要があります。composer.json の autoload の設定(psr-4 など)がプロジェクトのフォルダ構成と合っているか確認してください。

最小構成のサンプル

APIの基本情報と、1つのエンドポイントを定義する例です。

<?php
// src/OpenApi.php ── API全体の情報(1か所だけに書く)
namespace App;

use OpenApi\Attributes as OA;

#[OA\Info(
    version: '1.0.0',
    title: 'サンプル書籍API',
    description: '書籍情報を取得するAPI'
)]
#[OA\Server(url: 'https://api.example.com', description: '本番')]
class OpenApi
{
}
<?php
// src/Controller/BookController.php
namespace App\Controller;

use OpenApi\Attributes as OA;

class BookController
{
    #[OA\Get(
        path: '/books/{id}',
        summary: '書籍を1件取得する',
        tags: ['Books']
    )]
    #[OA\Parameter(
        name: 'id',
        in: 'path',
        required: true,
        description: '書籍ID',
        schema: new OA\Schema(type: 'integer', minimum: 1)
    )]
    #[OA\Response(
        response: 200,
        description: '取得できた',
        content: new OA\JsonContent(ref: '#/components/schemas/Book')
    )]
    #[OA\Response(response: 404, description: '書籍が見つからない')]
    public function show(int $id): void
    {
        // 実装
    }
}

#[OA\Info] はAPI全体の情報で、プロジェクトの中に1つだけ書きます。#[OA\Get] のように、HTTPメソッドごとに Get・Post・Put・Patch・Delete の属性があります。

スキーマ(データの形)を定義する

レスポンスのJSONの形は、モデルやDTOのクラスに書くと再利用できます。

<?php
// src/Model/Book.php
namespace App\Model;

use OpenApi\Attributes as OA;

#[OA\Schema(
    schema: 'Book',
    required: ['id', 'title'],
    properties: [
        new OA\Property(property: 'id', type: 'integer', example: 42),
        new OA\Property(property: 'title', type: 'string', example: 'PHP入門'),
        new OA\Property(property: 'published_at', type: 'string', format: 'date', nullable: true),
    ]
)]
class Book
{
}

schema: 'Book' で付けた名前を、エンドポイント側で ref: '#/components/schemas/Book' として参照します。配列で返す場合は new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/Book')) のように書きます。

example に実在の個人情報や本番データを書かないよう注意してください。ドキュメントは開発者以外の目にも触れることがあります。

認証の定義

Bearerトークン(JWTなど)で認証するAPIなら、認証方式を定義してエンドポイントに付けます。

#[OA\SecurityScheme(
    securityScheme: 'bearerAuth',
    type: 'http',
    scheme: 'bearer',
    bearerFormat: 'JWT'
)]
class OpenApi
{
}

// エンドポイント側
#[OA\Get(path: '/me', security: [['bearerAuth' => []]], summary: 'ログイン中のユーザー')]

ドキュメントに書くのは認証の「方式」だけです。トークンやAPIキーそのものを example などに書かないでください。

ドキュメントを生成する

スキャンするフォルダを指定して実行します。

vendor/bin/openapi src -o public/docs/openapi.yaml

# JSONで出力する場合
vendor/bin/openapi src -o public/docs/openapi.json --format json

生成されたファイルを開き、paths に /books/{id} が、components.schemas に Book が入っていれば成功です。

よく出るエラー

**Required @OA\Info() not found**#[OA\Info] が見つかっていません。スキャン対象のフォルダに OpenApi.php が入っているか、use OpenApi\Attributes as OA; が書かれているかを確認します。

**Required @OA\PathItem() not found**エンドポイントの定義が1つも見つかっていません。コントローラーのフォルダがスキャン対象に入っているか、クラスがオートロードで読み込めるか(名前空間とファイルの場所が一致しているか)を確認します。

**$ref "#/components/schemas/Book" not found**参照先のスキーマ名が違うか、モデルのフォルダがスキャン対象に入っていません。schema: に付けた名前と ref の綴りを見比べます。

警告やエラーの文言はバージョンで変わることがありますが、どれも「スキャン範囲」「オートロード」「名前の綴り」のどれかが原因であることが多いです。

Swagger UIで表示する

生成したファイルは、Swagger UIで読み込むと、エンドポイントの一覧や「実際にリクエストを送って試す」画面として表示できます。ローカルで確認するだけなら、Dockerの公式イメージが手軽です。

docker run --rm -p 8081:8080 \
  -e SWAGGER_JSON=/docs/openapi.yaml \
  -v "$(pwd)/public/docs:/docs" \
  swaggerapi/swagger-ui

ブラウザで http://localhost:8081 を開くと表示されます。Webサイトに組み込む場合は、npmの swagger-ui-dist パッケージを使って静的ファイルとして配置する方法もあります。読みやすさを重視するなら、Redocのような別の表示ツールを選ぶこともできます。

公開範囲に注意する

社内向けのAPIのドキュメントを誰でも見られる場所に置くと、存在を知られたくないエンドポイントまで公開することになります。社外に公開しないAPIなら、ドキュメントのURLにBasic認証やIP制限をかけるか、開発環境だけに置きます。Swagger UIの「試す」機能から本番のAPIにリクエストが送られる点も意識し、OA\Server の接続先を本番にするかどうかは慎重に決めてください。

CIでドキュメントを最新に保つ

生成を手作業にすると、いずれ更新が漏れます。CIで毎回生成し、検証まで行うと安心です。

# 生成して、リポジトリにあるファイルと差分があれば失敗させる例
vendor/bin/openapi src -o docs/openapi.yaml
git diff --exit-code docs/openapi.yaml

OpenAPIファイルの書き方の誤りや表記ゆれは、Spectralのようなリンター(ルールに沿ってファイルを検査するツール)で見つけられます。ここまで整えておくと、OpenAPI Generatorなどでクライアントのコードを自動生成する場合も安定します。

フレームワークを使っている場合

LaravelではL5-Swagger、SymfonyではNelmioApiDocBundleのように、swagger-phpを組み込んでルート設定と連携させるパッケージがあります。対応するフレームワークのバージョンや設定方法はパッケージごとに異なるため、導入前に各パッケージのドキュメントで対応状況を確認してください。

WordPressのREST APIは、OpenAPIではなく独自のスキーマ(register_rest_route() の args や schema)でエンドポイントを説明する仕組みです。WordPressのカスタムエンドポイントをOpenAPIで説明したい場合は、この記事の書き方を参考に別途定義する形になります。

まとめ

  • 作るのはOpenAPI形式のファイル、表示するのがSwagger UI。swagger-phpはPHPのコードからOpenAPIファイルを生成する
  • PHP 8.1以降なら属性(#[OA\...])で書く。対象のクラスはオートロードで読み込めるようにする
  • #[OA\Info] は1か所、エンドポイントは #[OA\Get] など、データの形は #[OA\Schema] で定義して ref で参照する
  • vendor/bin/openapi src -o openapi.yaml で生成し、エラーはスキャン範囲・オートロード・綴りの順に確認する
  • 社内APIのドキュメントは公開範囲を制限し、例示にトークンや個人情報を書かない
  • CIで生成と差分チェックを行い、ドキュメントの更新漏れを防ぐ

お気軽にご相談ください

お見積りへ お問い合わせへ
▲