juampi92 / api-resources
通过维护API版本管理来管理资源
Requires
- php: ^7.4|^8.0|^8.1|^8.2
- illuminate/http: ^7.0|^8.0|^9.0|^10.0
- illuminate/support: ^7.0|^8.0|^9.0|^10.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.8
- orchestra/testbench: ^5.0|^6.0|^7.0|^8.0
- phpstan/phpstan: ^1.9
- phpunit/phpunit: ^9.4
README
通过维护API版本管理来管理资源。使用简单的中间件,通过API版本分离路由,并智能实例化基于此版本的Http\Resources。
在api/v2组中添加中间件 'api.v:2'
。
然后 api_resource('App\User')->make($user)
与 new App\Http\Resources\App\v2\User($user)
相同,但版本自由。
App\Http\Resources\ |- App\ |- v1\ |- User.php |- v2\ |- Rank.php |- User.php
此想法的背景
一段时间前,我遇到了这个API版本管理问题,因此我写了一篇medium博客文章,其中包含我的解决方案,而这个包反映了这一点。
安装
您可以通过composer使用以下命令安装此包:
composer require juampi92/api-resources
此包将自动注册自己。
配置
要发布配置文件到 config/api.php
,运行以下命令:
php artisan vendor:publish --provider="Juampi92\APIResources\APIResourcesServiceProvider"
这将将在您的配置目录中发布一个包含以下内容的 api.php
文件:
return [ /* |-------------------------------------------------------------------------- | API Version |-------------------------------------------------------------------------- | | This value is the latest version of your api. This is used when | there's no specified version on the routes, so it will take this as the | default, or latest. */ 'version' => '1', /* |-------------------------------------------------------------------------- | Resources home path |-------------------------------------------------------------------------- | | This value is the base folder where your resources are stored. | When using multiple APIs, you can leave it as a string if every | api is in the same folder, or as an array with the APIs as keys. */ 'resources_path' => 'App\Http\Resources', /* |-------------------------------------------------------------------------- | Resources |-------------------------------------------------------------------------- | | Here is the folder that has versioned resources. If you store them | in the root of 'resources_path', leave this empty or null. */ 'resources' => 'App' ];
中间件
在您的 Http/Kernel.php
中的 $routeMiddleware
下安装此中间件
protected $routeMiddleware = [ ... 'api.v' => \Juampi92\APIResources\Middleware\APIversion::class, ... ];
正确配置
为了使此包正常工作,您需要了解它如何请求资源。
如果我们有以下配置:
[ 'version' => '2', 'resources_path' => 'App\Http\Resources', 'resources' => 'Api' ]
这意味着如果您包含 Api\User
资源,它将实例化 App\Http\Resources\Api\v2\User
。
Api
用于子组织结构,但您可以将版本化的资源文件夹放在根目录中,如下所示:
[ 'version' => '2', 'resources_path' => 'App\Http\Resources', 'resources' => '' ]
现在,如果我们包含 User
,它将实例化 App\Http\Resources\v2\User
。
回退
当您使用一个不是最新版本的版本时,如果您尝试包含在该版本目录中没有定义的资源,这会自动回退到 LATEST 版本。
这样,您就不必在之前的版本中复制新的资源。
用法
中间件
当您分组API路由时,您现在应该像这样将中间件 api.v
应用于组:
// App v1 API Route::group([ 'middleware' => ['app', 'api.v:1'], 'prefix' => 'api/v1', ], function ($router) { require base_path('routes/app_api.v1.php'); }); // App v2 API Route::group([ 'middleware' => ['app', 'api.v:2'], 'prefix' => 'api/v2', ], function ($router) { require base_path('routes/app_api.v2.php'); });
这样,如果您使用外观,您可以通过执行 APIResource::getVersion()
来检查当前版本,并返回中间件上指定的版本。
外观
有许多创建资源的方法。您可以使用外观访问器
use Juampi92\APIResources\Facades\APIResource; class SomethingController extends Controller { ... public function show(Something $model) { return APIResource::resolve('App\Something')->make($model); } }
全局助手
class SomethingController extends Controller { ... public function show(Something $model) { return api_resource('App\Something')->make($model); } }
集合
与 make
不同,对于数组,请使用 collection
,就像Laravel文档中所述。
class SomethingController extends Controller { ... public function index() { $models = Something::all(); return api_resource('App\Something')->collection($models); } }
如果您想使用ResourceCollection,您可能需要重写 collects()
方法。
class UserCollection extends ResourceCollection { protected function collects() { return APIResource::resolveClassname('App\User'); } }
这样,ResourceCollection将始终具有正确的类。
resolveClassname
将尝试使用类的当前版本,但如果不可能,将使用最新版本。
嵌套资源
为了利用 回退 功能,建议在资源中使用 api_resource
。这样,您可以保留正确的版本,或者如果未定义,则使用最新版本。
class Post extends Resource { public function toArray($request) { return [ 'title' => $this->title, ... 'user' => api_resource('App\User')->make($this->user); ]; } }
多个API
可能存在您在同一项目中拥有多个API的情况,但使用不同的版本。此应用支持这一点。首先,配置 config/api.php
:
return [ 'default' => 'api', 'version' => [ 'api' => '2', 'desktop' => '3' ], 'resources_path' => 'App\Http\Resources' // Or one path each 'resources_path' => [ 'api' => 'App\Http\Resources', 'desktop' => 'Vendorname\ExternalPackage\Resources' ], 'resources' => [ 'api' => 'Api', 'desktop' => '' ], ];
然后,您需要配置 中间件。现在,您不必使用 api.v:1
,而是必须指定名称:api.v:3,desktop
。
然后,其余部分按前面解释的方式工作。
API路由
有时您必须在API响应中返回路由URL。如果您想保留API版本(总是当前版本),api-resources为您提供了解决方案。
// When defining the routes Route::group([ 'middleware' => ['app', 'api.v:1'], 'prefix' => 'api/v1', // Using name on a group will prefix it. 'name' => 'api.v1.', ], function ($router) { Route::get('/auth/login', [ // This will be api.v1.auth.login 'name' => 'auth.login', 'use' => '...', ]); });
这样,在创建新版本时,我们就有api.v1.auth.login
和api.v2.auth.login
。
现在只需执行api_route('api.auth.login')
,它将相应地输出/api/v1/auth/login
或/api/v2/auth/login
。
工作原理
它获取配置api.resources
并进行小写转换,因此如果您有'resources' => 'App'
,则会将app.auth.login
转换为app.v1.auth.login
。如果您需要自定义它,请在config/api.php
中添加一个新的配置条目,如下所示
/* |-------------------------------------------------------------------------- | Route prefix |-------------------------------------------------------------------------- | | By default, the route prefix is the lowercase resources folder. | So it'd be `app.v1.auth.login` has the prefix `app`. | | Using `app` will do api_route(`app.auth.login`) => `app.v?.auth.login`. | */ 'route_prefix' => 'app'
它可以与多个API一起使用,如前所述。
测试
使用以下命令运行测试
vendor/bin/phpunit
致谢
许可证
MIT许可证(MIT)。有关更多信息,请参阅许可证文件