realtydev / laravel-swagger
自动为Laravel项目生成Swagger文档。
Requires
- php: >=7.2
- phpdocumentor/reflection-docblock: ^5.0
- swagger-api/swagger-ui: ^v3.51
Requires (Dev)
- ext-json: *
- laravel/passport: ^7.5 || ^8.0
- orchestra/testbench: ^3.8 || ^4.0
- phpunit/phpunit: ^8.5
- vimeo/psalm: ^3.9
Suggests
- ext-json: Required to use the JSON output option
- ext-yaml: Required to use the YAML output option
This package is auto-updated.
Last update: 2024-09-11 07:44:58 UTC
README
Laravel Swagger会扫描Laravel项目的端点,并自动为您生成Swagger 2.0文档。
关于
Laravel Swagger基于Laravel推荐的最佳实践。它将解析您的路由并为每个路由生成一个路径对象。如果您的控制器动作中注入了表单请求类作为请求验证,它还将为具有这些请求的每个请求生成参数。对于参数,它将考虑请求是GET/HEAD/DELETE还是POST/PUT/PATCH请求,并尽可能猜测应生成哪种参数对象类型。它还会生成包含在路由中的路径参数。最后,此包还将扫描您的动作方法中的任何文档,并将其作为摘要和描述添加到该路径中,同时添加任何适当的注释,如@deprecated。
请注意,此库倾向于明确性。即使有默认值,它也会选择包含键。例如,它选择说路由有一个已弃用的值为false,而不是将其省略。我相信这通过不省略重要信息使阅读文档变得更容易。如果用户选择省略默认值,文件可以很容易地进行清理。
默认情况下,生成的文档将可通过/docs
路由使用Swagger UI视图访问。
安装
您可以通过在项目根目录中运行composer require realtydev/laravel-swagger
轻松安装此包。
如果您正在运行Laravel < 5.5的版本,请确保将realtydev\LaravelSwagger\SwaggerServiceProvider::class
添加到config/app.php
中的providers
数组中。
这将注册可用的artisan命令。
您还可以通过在项目根目录中运行php artisan vendor:publish --provider "realtydev\LaravelSwagger\SwaggerServiceProvider"
来覆盖应用程序提供的默认配置,并更改新创建的config/laravel-swagger.php
文件中的配置。
配置
在文件config/laravel-swagger.php
中,您可以定义您的API版本,只需复制默认设置并根据需要更新即可。例如
[ // ... 'versions' => [ [ 'appVersion' => '1.0.0', 'host' => 'v1.myexample.com', 'basePath' => '/v1', 'schemes' => [ 'https', ], 'consumes' => [ 'application/json', ], 'produces' => [ 'application/json', ], 'ignoredMethods' => [ 'head', ], 'ignoredRoutes' => [ 'laravel-swagger.docs', 'laravel-swagger.asset' ], 'authFlow' => 'accessCode', 'security_definition_type' => 'oauth2', 'file_format' => 'json', 'errors_definitions' => [ 'UnprocessableEntity' => [ 'http_code' => 422, 'exception' => ValidationException::class, 'handler' => ValidationErrorDefinitionHandler::class ], 'Forbidden' => [ 'http_code' => 403, 'exception' => AuthorizationException::class, 'handler' => DefaultErrorDefinitionHandler::class ], 'NotFound' => [ 'http_code' => 404, 'exception' => ModelNotFoundException::class, 'handler' => DefaultErrorDefinitionHandler::class ], 'Unauthenticated' => [ 'http_code' => 401, 'exception' => AuthenticationException::class, 'handler' => DefaultErrorDefinitionHandler::class ], ], ], [ 'appVersion' => '2.0.0', 'host' => 'v2.myexample.com', 'basePath' => '/v2', 'schemes' => [ 'https', ], 'consumes' => [ 'application/json', ], 'produces' => [ 'application/json', ], 'ignoredMethods' => [ 'head', ], 'ignoredRoutes' => [ 'laravel-swagger.docs', 'laravel-swagger.asset' ], 'authFlow' => 'accessCode', 'security_definition_type' => 'jwt', 'file_format' => 'json', 'errors_definitions' => [ 'UnprocessableEntity' => [ 'http_code' => 422, 'exception' => ValidationException::class, 'handler' => ValidationErrorDefinitionHandler::class ], 'Forbidden' => [ 'http_code' => 403, 'exception' => AuthorizationException::class, 'handler' => DefaultErrorDefinitionHandler::class ], 'NotFound' => [ 'http_code' => 404, 'exception' => ModelNotFoundException::class, 'handler' => DefaultErrorDefinitionHandler::class ], 'Unauthenticated' => [ 'http_code' => 401, 'exception' => AuthenticationException::class, 'handler' => DefaultErrorDefinitionHandler::class ], ], ], ], ];
使用方法
要使定义生成工作,您需要迁移数据库表。在生成文档之前,请确保执行migrate
命令。
php artisan migrate
生成Swagger文档很简单,只需在项目根目录中运行php artisan laravel-swagger:generate
即可。
默认情况下,该命令将为在config/laravel-swagger.php
中定义的所有版本生成文档。
您可以通过传递参数--api-version=
来过滤到特定版本。例如
php artisan laravel-swagger:generate --api-version=2.0.0 # must match the version defined in the configs
默认情况下,laravel-swagger以json格式生成文档,如果您想以YAML格式生成,可以使用--format
标志覆盖格式。如果选择这样做,请确保已安装yaml扩展。
支持的格式选项有
json
yaml
生成文档后,访问路由/docs
以查看API文档。默认情况下将显示最新版本的API,但您可以在屏幕上选择版本或通过路径参数传递版本。例如:/docs/2.0.0
。
示例
假设您有一个路由 /api/users/{id}
,它映射到 UserController@show
您的示例控制器可能看起来像这样
/** * Return all the details of a user * * Returns the user's first name, last name and address * Please see the documentation [here](https://example.com/users) for more information * * @deprecated */ class UserController extends Controller { public function show(UserShowRequest $request, $id) { return User::find($id); } }
FormRequest 类可能看起来像这样
class UserShowRequest extends FormRequest { public function rules() { return [ 'fields' => 'array', 'show_relationships' => 'boolean|required' ]; } }
运行 php artisan laravel-swagger:generate
将在公共路径上生成一个包含以下定义的文件
{ "swagger": "2.0", "info": { "title": "Laravel", "description": "Test", "version": "1.0.1" }, "host": "http:\/\/localhost", "basePath": "\/", "paths": { "\/api\/user\/{id}": { "get": { "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 "responses": { "200": { "description": "OK" } }, "parameters": [ { "in": "path", "name": "id", "type": "integer", "required": true, "description": "" }, { "in": "query", "name": "fields", "type": "array", "required": false, "description": "" }, { "in": "query", "name": "show_relationships", "type": "boolean", "required": true, "description": "" } ] }, ... } } }
定义
您可以在方法或控制器/类的文档中使用完整模型路径来定义注解 @model
(适用于所有方法)。这将生成对模型在响应中的引用,例如
// Model definition on method: class OrderController { /** * @param int $id * @model App\Models\Order */ public function show(int $id) { // ... } } // Model definition on Controller: /** * Class ProductController * @model App\Models\Product */ class ProductController { /** * @param int $id */ public function show(int $id) { // ... } }
模型
模型定义字段将从 Schema::getColumnListing($model->getTable())
函数返回的 columns
表中获取。
如果您想使用 $appends
属性的字段,请在您的模型类中使用 trait 'realtydev\LaravelSwagger\Traits\HasAppends'。例如
use realtydev\LaravelSwagger\Traits\HasAppends; class MyModel extends Model { use HasAppends; // ... }
如果模型有一个关联的 factory,并且您在配置中启用了 generateExampleData
选项,则将为定义的每个字段生成 example
数据。
警告:我们使用数据库事务来生成此数据。尽管数据不会保存到数据库中,但建议您在开发环境中使用此功能,以避免任何意外的副作用。
将过滤列以删除具有 $hidden
属性的字段。
如果您启用了 parseModelRelationships
选项,并且如果关系方法包含 Relationship
返回类型提示,则将模型关系添加到定义中。
警告:为了获取关系的关联模型,我们必须调用该方法。确保调用这些方法时没有副作用,并且它们只返回关系。
例如
// Tables structure: Schema::create('products', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->decimal('price'); $table->boolean('active'); $table->timestamp('finished_at'); $table->timestamps(); }); Schema::create('orders', function (Blueprint $table) { $table->bigIncrements('id'); $table->decimal('value'); $table->unsignedBigInteger('product_id'); $table->foreign('product_id') ->references('id') ->on('products'); $table->timestamps(); }); // Models use Illuminate\Database\Eloquent\Relations; use realtydev\LaravelSwagger\Traits\HasAppends; class Order extends Model { use HasAppends; protected $fillable = [ 'value', ]; protected $casts = [ 'value' => 'float', 'formatted_value' => 'string', ]; protected $appends = [ 'formatted_value', ]; public function getFormattedValueAttribute() { return '$ ' . $this->value; } public function product() : Relations\BelongsTo { return $this->belongsTo(Product::class); } } class Product extends Model { protected $fillable = [ 'name', 'price', 'active', ]; protected $hidden = [ 'active', ]; protected $casts = [ 'name' => 'string', 'price' => 'float', 'active' => 'boolean', ]; protected $dates = [ 'finished_at', ]; public function orders() : Relations\HasMany { return $this->hasMany(Order::class); } }
上面的结构将返回以下定义
{ "Order": { "type": "object", "properties": { "id": { "type": "integer", "example": "1" }, "value": { "type": "number", "format": "float", "example": "16.54" }, "product_id": { "type": "string" }, "customer_id": { "type": "string" }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" }, "formatted_value": { "type": "string" }, "product": { "$ref": "#/definitions/Product" } } }, "Product": { "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" }, "price": { "type": "number", "format": "float" }, "finished_at": { "type": "string", "format": "date-time" }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" }, "orders": { "type": "array", "items": { "$ref": "#/definitions/Order" } } } } }
将使用属性 $casts
来定义属性 type
和 format
。如果没有定义任何类型转换,将使用默认类型 string
。
响应
响应将根据路由的 http 方法、@throws
注解和 auth
中间件来定义。例如
// Routes Route::get('/customers', 'CustomerController@index') ->name('customers.index') ->middleware('auth:api'); Route::get('/customers', 'CustomerController@store') ->name('customers.store'); Route::put('/customers/{id}', 'CustomerController@update') ->name('customers.update'); // Controller use App\Http\Requests\StoreCustomerRequest; use App\Http\Requests\UpdateCustomerRequest; /** * Class CustomerController * @model App\Customer */ class CustomerController extends Controller { public function __construct() { $this->middleware('auth:api'); } public function index() { } public function store(StoreCustomerRequest $request) { } /** * @param int $id * @param UpdateCustomerRequest $request * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException * @throws \Illuminate\Auth\AuthenticationException * @throws \Illuminate\Auth\Access\AuthorizationException */ public function update(int $id, UpdateCustomerRequest $request) { // ... } }
上面的定义将生成以下响应
获取所有客户
{ "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { "$ref": "#/definitions/Customer" } } }, "401": { "description": "Unauthenticated" } } }
存储客户
{ "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/Customer" } }, "422": { "description": "Validation errors" } } }
更新客户
{ "responses": { "204": { "description": "No Content" }, "422": { "description": "Validation errors" }, "404": { "description": "Model not found" }, "401": { "description": "Unauthenticated" }, "403": { "description": "Forbidden" } } }