wilkques/openapi

自动为 Laravel 项目生成 Swagger.io 文档

v3.0.0 2024-06-18 09:02 UTC

README

Laravel OAS3 扫描您的 Laravel 项目的端点,并自动为您生成 OAS3 文档。

TESTS Latest Stable Version License

关于

本包深受 mtrajano/laravel-swagger 启发。

使用方式与 mtrajano/laravel-swagger 非常相似

Laravel OAS3 基于Laravel推荐的最佳实践。它将解析您的路由并为每个路由生成一个路径对象。如果您在控制器操作中注入表单请求类作为请求验证,它也将为具有它们的每个请求生成参数。对于参数,它将考虑请求是GET/HEAD/DELETE还是POST/PUT/PATCH请求,并尽可能猜测应该生成哪种类型的参数对象。它还会生成包含在路由中的路径参数。最后,此包还将扫描您的操作方法中的任何文档,并将其添加为路径的摘要和描述,以及任何适当的注释,如@deprecated。

请注意,此库侧重于明确性。它甚至包括具有默认值的键。例如,它选择说明路由具有已弃用的值为false,而不是将其省略。我相信这使阅读文档更容易,因为它不会省略重要信息。用户可以选择删除默认值以轻松清理文件。

安装

您可以通过在项目根目录中运行 composer require wilkques/openapi 简单地安装此包。

如果您正在运行Laravel版本 < 5.5,请确保将 Wilkques\OpenAPI\OpenAPIServiceProvider::class 添加到 config/app.php 中的 providers 数组。

这将注册可用的 artisan 命令。

您还可以通过在项目根目录中运行 php artisan vendor:publish --provider "Wilkques\OpenAPI\OpenAPIServiceProvider" 来覆盖应用程序提供的默认配置,并更改新创建的 config/openapi.php 文件中的配置。

使用

生成 OpenAPI 文档非常简单,只需在项目根目录中运行 php artisan openapi:generate 即可。请注意,该命令将在控制台中打印输出。如果要将文档保存到文件中,您可以像这样重定向输出:php artisan openapi:generate > openapi.json

如果您希望为您的路由子集生成文档,可以使用 --filter--except 传递过滤器,例如:php artisan openapi:generate --filter="/api" --except="/api/v1"

默认情况下,laravel-openapi 以json格式打印文档。如果要以YAML格式输出,您可以使用 --format 标志覆盖格式。如果选择这样做,请确保已安装yaml扩展。

格式选项有
json
yaml

示例

假设您有一个路由 /api/users/{id},它映射到 UserController@show

您的示例控制器可能如下所示

@Response() @Request() @Servers() @Path() 输入json格式或yaml格式(需要php YAML扩展)

/**
 * @Servers([
 *      {
 *          "url": "{schema}://example.com",
 *          "description": "local server",
 *          "variables": {
 *              "schema": {
 *                  "enum": ["https", "http"],
 *                  "default": "http"
 *              }
 *          }
 *      }
 * ])
 */
class TestController extends Controller
{
    /**
     * test controller
     * 
     * @Path({
     *      "id": {
     *          "description": "id",
     *          "example": "123456789"
     *      }
     * })
     * @Request({
     *      "summary": "test get /api/test index",
     *      "description": "Test route description",
     *      "tags": ["User"],
     *      "security": [{"bearerAuth": []}]
     * })
     * @Response({
     *     "code": 302
     * })
     * @Response({
     *     "code": 400
     * })
     * @Response({
     *     "code": 500
     * })
     * @Response({
     *      "code": 200,
     *      "body": {
     *          "data": {
     *              "type": "array",
     *              "items": {
     *                  "type": "object",
     *                  "properties": {
     *                      "id": {
     *                          "type": "integer",
     *                          "description": "file id",
     *                          "example": 1
     *                      },
     *                      "name": {
     *                          "type": "string",
     *                          "description": "file name",
     *                          "example": "name"
     *                      }
     *                  }
     *              }
     *          }
     *      }
     * })
     */
    public function update(UserUpdateRequest $request)

    // or

    /**
     * test yaml controller
     * 
     * @Path(
     *      id:
     *          description: "id"
     *          example: 123456789
     * 
     * )
     * @Request(
     *      summary: "test get /api/test index"
     *      description: "Test route descriptioncd"
     *      tags:
     *      - "User"
     *      security: 
     *      - bearerAuth: []
     * )
     * @Response(
     *     code: 302
     * )
     * @Response(
     *     code: 400
     * )
     * @Response(
     *     code: 500
     * )
     * @Response(
     *      code: 200
     *      body:
     *          data:
     *              type: "array"
     *              items:
     *                  type: "object"
     *                  properties:
     *                      id:
     *                          type: "integer"
     *                          description: "file id"
     *                          example: 1
     *                      name: 
     *                          type: "string"
     *                          description: "file name"
     *                          example: "name"
     * )
     */
    public function yaml()

或自定义请求

/**
 * @Request({
 *      "summary": "test get /api/test index",
 *      "description": "Test route description",
 *      "tags": ["Test"],
 *      "security": [{"bearerAuth": []}],
 *      "parameters": [
 *          {
 *              "in": "query",
 *              "name": "test",
 *              "required": "false",
 *              "description": "Test description",
 *              "schema": {
 *                  "type": "string",
 *                  "enum": [1, 2],
 *                  "example": "1"
 *              }
 *          }
 *      ],
 *      "requestBody": {
 *          "custom": "only", // If the value of the custom parameter is "only", then display only the custom parameters. If the value is "merge", then merge the custom parameters with the results of the FormRequest. The default value is "merge".
 *          "content": {
 *              "multipart/form-data": {
 *                  "schema": {
 *                      "type": "object",
 *                      "required": ["file"],
 *                      "properties": {
 *                          "file":{
 *                              "type": "string",
 *                              "format": "binary",   
 *                              "description": "file upload" 
 *                          },
 *                          "content":{
 *                              "type": "string"
 *                          }
 *                      }
 *                  }
 *              }
 *          }
 *      }
 * })
 */
public function store(StoreRequest $request)

如果您不希望生成路由,可能如下所示

/**
 * @exclude
 */ 
public function destroy($id)

编辑 config/openapi.php

'only' => [
    'namespace' => [
        // 'App\Http\Controllers',
    ],
],

'exclude' => [
    'routes' => [
        'uri'   => [
            // route uri
        ],
        'name'  => [
            // route name or as
        ]
    ],
],

FormRequest 类可能看起来像这样

@Fields() 输入 json 字符串或 yaml 格式(需要 php YAML 扩展)

class UserUpdateRequest extends FormRequest
{
    /**
     * @Fields({
     *      "test": {
     *          "description": "Test description",
     *          "example": 1
     *      }
     * })
     */
    public function rules()
    {
        return [
            'test'          => 'in:1,2',
            'file.*.name'   => 'required|string',
            'file.*.path'   => 'required|string',
        ];
    }
}

运行 artisan openapi:generate --output=storage/api-docs/api-docs.json 将生成以下文件

{
    "openapi": "3.0.3",
    "info": {
        "title": "Laravel",
        "description": "Test",
        "version": "1.0.1"
    },
    "servers": [
        {
            "url": "\/",
            "description": "server",
            "variables": {
                "schema": {
                    "enum": [
                        "https",
                        "http"
                    ],
                    "default": "http"
                }
            }
        }
    ],
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "bearerFormat": "JWT"
            }
        }
    },
    "paths": {
        "\/api\/user\/{id}": {
            "put": {
                "summary": "Return all the details of a user",
                "description": "Returns the user's first name, last name and address
 Please see the documentation [here](https://example.com/users) for more information",
                "deprecated": true,
                "security": [{
                    "bearerAuth": []
                }],
                "tags": ["User"],
                "parameters": [
                    {
                        "in": "path",
                        "name": "id",
                        "required": true,
                        "description": "",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "in": "query",
                        "name": "test",
                        "required": false,
                        "description": "Test description",
                        "schema": {
                            "type": "enum",
                            "enum": ["1","2"],
                            "example": 1
                        }
                    }
                ],
                "requestBody": {
                    "content": {
                        "application\/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "file.*.name",
                                    "file.*.path"
                                ],
                                "properties": {
                                    "file": {
                                        "type": "array",
                                        "items": {
                                            "type": "object",
                                            "properties": {
                                                "name": {
                                                    "type": "string",
                                                    "description": "Test file name",
                                                    "example": "file name"
                                                },
                                                "path": {
                                                    "type": "string",
                                                    "description": "Test file path",
                                                    "example": "file path"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "302": {
                        "description": "Found"
                    },
                    "400": {
                        "description": "Bad Request"
                    },
                    "500": {
                        "description": "Internal Server Error"
                    },
                    "200": {
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "id": {
                                                        "type": "integer",           
                                                        "description": "file id",
                                                        "example": 1
                                                    },
                                                    "name": {
                                                        "type": "string",           
                                                        "description": "file name",
                                                        "example": "name"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        },
                        "description": "OK"
                    }
                }
            },
        }
    }
}

参考