31
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Swagger-PHPでSwagger2.0に対応したアノテーションサンプル

Last updated at Posted at 2016-04-11

swagger & swagger-php & swagger-ui

swagger-phpを使ってswagger形式のAPIドキュメントを作成し、swagger-uiを使って参照・実行したい。
(概要、セットアップ等は以前の内容を参照ください。。)

swagger-phpで、swagger2.0に対応したドキュメントは下記の2つくらい??

ちょっと試行錯誤しながらの部分もあったのでメモとして残しておきます。。

環境

  • FuelPHP

  • APIのURLは192.168.99.100:81

  • ユーザータグというリソースを扱うAPIで、エンドポイントはユーザ関連のCRUDをひととおり作るイメージ

アノテーションサンプル

コントローラ

API全体の定義と、各エンドポイントの定義を記述していく。
基底クラスと各コントローラに別れるので、それぞれに記述する。

  • コントローラの基底クラス
app/classes/controller/base.php
use Swagger\Annotations as SWG;

/**
 * @SWG\Swagger(
 *   schemes={"http"},
 *   host="192.168.99.100:81",
 *   basePath="",
 *   @SWG\Info(
 *     version="1.0.0",
 *     title="sample API",
 *     description="サンプルAPIでswaggerを試す",
 *     @SWG\Contact(
 *       email=""
 *     ),
 *     @SWG\License(
 *       name="",
 *       url=""
 *     )
 *   ),
 *   @SWG\ExternalDocumentation(
 *     description="Find out more about Swagger",
 *     url="http://swagger.io"
 *   )
 * )
 *
 * タグ(エンドポイントのグルーピング)
 * @SWG\Tag(
 *   name="user",
 *   description="ユーザー関連"
 * )
 * @SWG\Tag(
 *   name="tag",
 *   description="タグ関連"
 * )
 *
 * 認証関連
 * @SWG\SecurityScheme(
 *   securityDefinition="api_key",
 *   type="apiKey",
 *   in="header",
 *   name="api_key"
 * )
 *
 * API全体で共通なクエリパラメータ
 * @SWG\Parameter(
 *     name="order",
 *     description="取得順序",
 *     in="query",
 *     required=false,
 *     type="string"
 * )
 * @SWG\Parameter(
 *     name="limit",
 *     description="取得件数",
 *     in="query",
 *     required=false,
 *     type="integer",
 *     format="int32"
 * )
 * @SWG\Parameter(
 *     name="offset",
 *     description="取得開始位置",
 *     in="query",
 *     required=false,
 *     type="integer",
 *     format="int32"
 * )
 *
 * 共通レスポンスとしてここに定義して後から呼び出せるかと思ったらダメだった。。
 * @SWG\Response(response=200, description="OK")
 * @SWG\Response(response=201, description="Created")
 * @SWG\Response(response=202, description="Accepted")
 * @SWG\Response(response=204, description="No Content")
 * @SWG\Response(response=207, description="Multi-Status")
 * @SWG\Response(response=304, description="Not Modified")
 * @SWG\Response(response=400, description="Bad Request")
 * @SWG\Response(response=401, description="Unauthorized")
 * @SWG\Response(response=403, description="Forbidden")
 * @SWG\Response(response=405, description="Method Not Allowed")
 * @SWG\Response(response=500, description="Internal Server Error")
 * @SWG\Response(response=503, description="Service Unavailable")
 */
class Controller_Base extends Controller_Rest
{
}
  • ユーザーコントローラ
    • とりあえずgetとpostの雰囲気だけ。。
app/classes/controller/user.php
class Controller_User extends Controller_Base
{
	 /**
	 * @SWG\Get(
	 *   path="/users",
	 *   summary="ユーザ一覧",
	 *   tags={"user"},
	 *   description="ユーザの一覧を取得する",
	 *   consumes={"application/json", "application/xml"},
	 *   produces={"application/json", "application/xml"},
	 *   @SWG\Parameter(ref="#/parameters/order"),
	 *   @SWG\Parameter(ref="#/parameters/limit"),
	 *   @SWG\Parameter(ref="#/parameters/offset"),
	 *   @SWG\Parameter(
	 *     name="id",
	 *     in="query",
	 *     description="Id指定(CSV複数可能)",
	 *     required=false,
	 *     type="array",
	 *     @SWG\Items(type="integer", format="int32"),
	 *     collectionFormat="csv"
	 *   ),
	 *   @SWG\Parameter(
	 *     name="status",
	 *     in="query",
	 *     description="ステータス指定",
	 *     required=false,
	 *     type="string",
     *     enum={"available", "pending", "sold"}
	 *   ),
	 *   @SWG\Response(
	 *     response=200,
	 *     description="OK",
	 *     @SWG\Schema(
	 *       type="array",
	 *       @SWG\Items(ref="#/definitions/User")
	 *     )
	 *   ),
	 *   @SWG\Response(response=400, description="Bad Request"),
	 *   @SWG\Response(response=500, description="Internal Server Error")
	 * )
	 */
	public function get_list()
	{
	}

	/**
	 * @SWG\Post(
	 *   path="/users",
	 *   summary="ユーザ作成",
	 *   tags={"user"},
	 *   description="ユーザ作成",
     *   @SWG\Parameter(
     *     in="body",
     *     name="body",
     *     description="登録するユーザデータ",
     *     required=true,
     *     @SWG\Schema(
	 *       type="array",
	 *       @SWG\Items(ref="#/definitions/User")
     *     )
     *   ),
	 *   @SWG\Response(
	 *     response=201,
	 *     description="Created",
	 *     @SWG\Schema(
	 *       type="array",
	 *       @SWG\Items(ref="#/definitions/User")
	 *     )
	 *   ),
	 *   @SWG\Response(
	 *     response=207,
	 *     description="Multi-Status",
	 *     @SWG\Schema(
	 *       type="object",
	 *       @SWG\Property(property="error_code", type="integer", format="int32"),
	 *       @SWG\Property(property="error_message", type="string")
	 *     )
	 *   ),
	 *   @SWG\Response(response=400, description="Bad Request"),
	 *   @SWG\Response(response=500, description="Internal Server Error")
	 * )
	 */
	public function post_list()
	{
	}

	/**
	 * @SWG\Get(
	 *   path="/users/{id}",
	 *   summary="ユーザ詳細",
	 *   tags={"user"},
	 *   description="ユーザの詳細情報を取得する",
	 *   consumes={"application/json", "application/xml"},
	 *   produces={"application/json", "application/xml"},
	 *   @SWG\Parameter(
	 *     name="id",
	 *     in="path",
	 *     description="ユーザID",
	 *     required=true,
	 *     type="integer",
	 *     format="int32",
	 *   ),
	 *   @SWG\Response(
	 *     response=200,
	 *     description="OK",
	 *     @SWG\Schema(ref="#/definitions/User")
	 *   ),
	 *   @SWG\Response(response=400, description="Bad Request"),
	 *   @SWG\Response(response=500, description="Internal Server Error")
	 * )
	 */
	public function get_detail($id)
	{
	}

	/**
	 * @SWG\Put(
	 *   path="/users/{id}",
	 *   summary="update user",
	 *   tags={"user"},
	 *   description="update user",
	 *   @SWG\Parameter(
	 *     name="id",
	 *     in="path",
	 *     description="ユーザID",
	 *     required=true,
	 *     type="integer",
	 *     format="int32",
	 *   ),
     *   @SWG\Parameter(
     *     in="body",
     *     name="body",
     *     description="置換更新するユーザデータ",
     *     required=true,
     *     @SWG\Schema(ref="#/definitions/User")
     *   ),
	 *   @SWG\Response(
	 *     response=201,
	 *     description="Created",
	 *     @SWG\Schema(ref="#/definitions/User")
	 *   ),
	 *   @SWG\Response(response=400, description="Bad Request"),
	 *   @SWG\Response(response=500, description="Internal Server Error")
	 * )
	 */
	public function put_detail($id)
	{
	}

	/**
	 * @SWG\Patch(
	 *   path="/users/{id}",
	 *   summary="patch user",
	 *   tags={"user"},
	 *   description="patch user",
	 *   @SWG\Parameter(
	 *     name="id",
	 *     in="path",
	 *     description="ユーザID",
	 *     required=true,
	 *     type="integer",
	 *     format="int32",
	 *   ),
     *   @SWG\Parameter(
     *     in="body",
     *     name="body",
     *     description="部分更新するユーザデータ",
     *     required=true,
     *     @SWG\Schema(ref="#/definitions/User")
     *   ),
	 *   @SWG\Response(
	 *     response=201,
	 *     description="Created",
	 *     @SWG\Schema(ref="#/definitions/User")
	 *   ),
	 *   @SWG\Response(response=400, description="Bad Request"),
	 *   @SWG\Response(response=500, description="Internal Server Error")
	 * )
	 */
	public function patch_detail($id)
	{
	}

	/**
	 * @SWG\Delete(
	 *   path="/users/{id}",
	 *   summary="delete user",
	 *   tags={"user"},
	 *   description="delete user",
	 *   @SWG\Parameter(
	 *     name="id",
	 *     in="path",
	 *     description="ユーザID",
	 *     required=true,
	 *     type="integer",
	 *     format="int32",
	 *   ),
	 *   @SWG\Response(
	 *     response=204,
	 *     description="No Content"
	 *   ),
	 *   @SWG\Response(response=400, description="Bad Request"),
	 *   @SWG\Response(response=500, description="Internal Server Error")
	 * )
	 */
	public function delete_detail($id)
	{
	}
}

リソース

今回のAPIでは、APIであつかうデータをfuel/app/classes/resource内にクラス定義することにした。
fuel/app/classes/modelは通常どおりDBモデルの定義に使用)

app/classes/resource/base.php
use Swagger\Annotations as SWG;
app/classes/resource/user.php
/**
 * @SWG\Definition(definition="User", type="object")
 */
class Resource_User extends Resource_Base
{
	/**
	 * @SWG\Property(property="id", type="integer", format="int32")
	 * @var int
	 */
	public $id;

	/**
	 * @SWG\Property(property="name", type="integer", format="int32")
	 * @var string
	 */
	public $name;

	/**
	 * @SWG\Property(property="status", type="string", enum={"available", "pending", "sold"})
	 * @var string
	 */
	public $status;

	/**
	 * @SWG\Property(property="tags", type="array", @SWG\Items(ref="#/definitions/Tag"))
	 * @var Tag[]
	 */
	public $tags;
}
app/classes/resource/tag.php
/**
 * @SWG\Definition(definition="Tag", type="object")
 */
class Resource_Tag extends Resource_Base
{
	/**
	 * @SWG\Property(property="id", type="integer", format="int32")
	 * @var int
	*/
	public $id;

	/**
	 * @SWG\Property(property="tag", type="string")
	 * @var string
	 */
	public $tag;
}

JSON出力

出力されたJSONがこちら

swagger.json
{
    "swagger": "2.0",
    "info": {
        "title": "sample API",
        "description": "\u30b5\u30f3\u30d7\u30ebAPI\u3067swagger\u3092\u8a66\u3059",
        "contact": {
            "email": ""
        },
        "license": {
            "name": "",
            "url": ""
        },
        "version": "1.0.0"
    },
    "host": "192.168.99.100:81",
    "basePath": "",
    "schemes": [
        "http"
    ],
    "paths": {
        "/users": {
            "get": {
                "tags": [
                    "user"
                ],
                "summary": "\u30e6\u30fc\u30b6\u4e00\u89a7",
                "description": "\u30e6\u30fc\u30b6\u306e\u4e00\u89a7\u3092\u53d6\u5f97\u3059\u308b",
                "consumes": [
                    "application/json",
                    "application/xml"
                ],
                "produces": [
                    "application/json",
                    "application/xml"
                ],
                "parameters": [
                    {
                        "$ref": "#/parameters/order"
                    },
                    {
                        "$ref": "#/parameters/limit"
                    },
                    {
                        "$ref": "#/parameters/offset"
                    },
                    {
                        "name": "id",
                        "in": "query",
                        "description": "Id\u6307\u5b9a\uff08CSV\u8907\u6570\u53ef\u80fd\uff09",
                        "required": false,
                        "type": "array",
                        "items": {
                            "type": "integer",
                            "format": "int32"
                        },
                        "collectionFormat": "csv"
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "description": "\u30b9\u30c6\u30fc\u30bf\u30b9\u6307\u5b9a",
                        "required": false,
                        "type": "string",
                        "enum": [
                            "available",
                            "pending",
                            "sold"
                        ]
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/User"
                            }
                        }
                    },
                    "400": {
                        "description": "Bad Request"
                    },
                    "500": {
                        "description": "Internal Server Error"
                    }
                }
            },
            "post": {
                "tags": [
                    "user"
                ],
                "summary": "\u30e6\u30fc\u30b6\u4f5c\u6210",
                "description": "\u30e6\u30fc\u30b6\u4f5c\u6210",
                "parameters": [
                    {
                        "name": "body",
                        "in": "body",
                        "description": "\u767b\u9332\u3059\u308b\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf",
                        "required": true,
                        "schema": {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/User"
                            }
                        }
                    }
                ],
                "responses": {
                    "201": {
                        "description": "Created",
                        "schema": {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/User"
                            }
                        }
                    },
                    "207": {
                        "description": "Multi-Status",
                        "schema": {
                            "properties": {
                                "error_code": {
                                    "type": "integer",
                                    "format": "int32"
                                },
                                "error_message": {
                                    "type": "string"
                                }
                            },
                            "type": "object"
                        }
                    },
                    "400": {
                        "description": "Bad Request"
                    },
                    "500": {
                        "description": "Internal Server Error"
                    }
                }
            }
        },
        "/users/{id}": {
            "get": {
                "tags": [
                    "user"
                ],
                "summary": "\u30e6\u30fc\u30b6\u8a73\u7d30",
                "description": "\u30e6\u30fc\u30b6\u306e\u8a73\u7d30\u60c5\u5831\u3092\u53d6\u5f97\u3059\u308b",
                "consumes": [
                    "application/json",
                    "application/xml"
                ],
                "produces": [
                    "application/json",
                    "application/xml"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "\u30e6\u30fc\u30b6ID",
                        "required": true,
                        "type": "integer",
                        "format": "int32"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/User"
                        }
                    },
                    "400": {
                        "description": "Bad Request"
                    },
                    "500": {
                        "description": "Internal Server Error"
                    }
                }
            },
            "put": {
                "tags": [
                    "user"
                ],
                "summary": "update user",
                "description": "update user",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "\u30e6\u30fc\u30b6ID",
                        "required": true,
                        "type": "integer",
                        "format": "int32"
                    },
                    {
                        "name": "body",
                        "in": "body",
                        "description": "\u7f6e\u63db\u66f4\u65b0\u3059\u308b\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf",
                        "required": true,
                        "schema": {
                            "items": {
                                "$ref": "#/definitions/User"
                            }
                        }
                    }
                ],
                "responses": {
                    "201": {
                        "description": "Created",
                        "schema": {
                            "$ref": "#/definitions/User"
                        }
                    },
                    "400": {
                        "description": "Bad Request"
                    },
                    "500": {
                        "description": "Internal Server Error"
                    }
                }
            },
            "delete": {
                "tags": [
                    "user"
                ],
                "summary": "delete user",
                "description": "delete user",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "\u30e6\u30fc\u30b6ID",
                        "required": true,
                        "type": "integer",
                        "format": "int32"
                    }
                ],
                "responses": {
                    "204": {
                        "description": "No Content"
                    },
                    "400": {
                        "description": "Bad Request"
                    },
                    "500": {
                        "description": "Internal Server Error"
                    }
                }
            },
            "patch": {
                "tags": [
                    "user"
                ],
                "summary": "patch user",
                "description": "patch user",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "description": "\u30e6\u30fc\u30b6ID",
                        "required": true,
                        "type": "integer",
                        "format": "int32"
                    },
                    {
                        "name": "body",
                        "in": "body",
                        "description": "\u90e8\u5206\u66f4\u65b0\u3059\u308b\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf",
                        "required": true,
                        "schema": {
                            "items": {
                                "$ref": "#/definitions/User"
                            }
                        }
                    }
                ],
                "responses": {
                    "201": {
                        "description": "Created",
                        "schema": {
                            "$ref": "#/definitions/User"
                        }
                    },
                    "400": {
                        "description": "Bad Request"
                    },
                    "500": {
                        "description": "Internal Server Error"
                    }
                }
            }
        }
    },
    "definitions": {
        "Tag": {
            "properties": {
                "id": {
                    "type": "integer",
                    "format": "int32"
                },
                "tag": {
                    "type": "string"
                }
            },
            "type": "object"
        },
        "User": {
            "properties": {
                "id": {
                    "type": "integer",
                    "format": "int32"
                },
                "name": {
                    "type": "integer",
                    "format": "int32"
                },
                "status": {
                    "type": "string",
                    "enum": [
                        "available",
                        "pending",
                        "sold"
                    ]
                },
                "tags": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/Tag"
                    }
                }
            },
            "type": "object"
        }
    },
    "parameters": {
        "order": {
            "name": "order",
            "in": "query",
            "description": "\u53d6\u5f97\u9806\u5e8f",
            "required": false,
            "type": "string"
        },
        "limit": {
            "name": "limit",
            "in": "query",
            "description": "\u53d6\u5f97\u4ef6\u6570",
            "required": false,
            "type": "integer",
            "format": "int32"
        },
        "offset": {
            "name": "offset",
            "in": "query",
            "description": "\u53d6\u5f97\u958b\u59cb\u4f4d\u7f6e",
            "required": false,
            "type": "integer",
            "format": "int32"
        }
    },
    "responses": {
        "200": {
            "description": "OK"
        },
        "201": {
            "description": "Created"
        },
        "202": {
            "description": "Accepted"
        },
        "204": {
            "description": "No Content"
        },
        "207": {
            "description": "Multi-Status"
        },
        "304": {
            "description": "Not Modified"
        },
        "400": {
            "description": "Bad Request"
        },
        "401": {
            "description": "Unauthorized"
        },
        "403": {
            "description": "Forbidden"
        },
        "405": {
            "description": "Method Not Allowed"
        },
        "500": {
            "description": "Internal Server Error"
        },
        "503": {
            "description": "Service Unavailable"
        }
    },
    "securityDefinitions": {
        "api_key": {
            "type": "apiKey",
            "name": "api_key",
            "in": "header"
        }
    },
    "tags": [
        {
            "name": "user",
            "description": "\u30e6\u30fc\u30b6\u30fc\u95a2\u9023"
        },
        {
            "name": "tag",
            "description": "\u30bf\u30b0\u95a2\u9023"
        }
    ],
    "externalDocs": {
        "description": "Find out more about Swagger",
        "url": "http://swagger.io"
    }
}

これをswagger-uiに読み込ませると、クエリパラメータやリクエストボディ、レスポンスの定義も表示されるかと思います。


(追記)

  • 日付
 *   @SWG\Parameter(
 *     name="id",
 *     in="path",
 *     description="ユーザID",
 *     required=true,
 *     type="string",
 *     format="date"
 *   )
  • 日時
 *   @SWG\Parameter(
 *     name="id",
 *     in="path",
 *     description="ユーザID",
 *     required=true,
 *     type="string",
 *     format="date-time"
 *   )
31
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?