Open guanguans opened 1 week ago
laravel-api-response - 规范化和标准化 Laravel API 响应数据结构。
guanguans/laravel-api-response
composer require guanguans/laravel-api-response --ansi -v
php artisan vendor:publish --provider="Guanguans\\LaravelApiResponse\\ServiceProvider" --ansi -v
laravel-api-response - 规范化和标准化 Laravel API 响应数据结构
源码
guanguans/laravel-api-response
功能
环境要求
安装
配置
发布文件(可选)
使用
快速开始
详情
```php middleware(SetAcceptHeader::class)->only('exceptionHandler'); } public function getInstance(): JsonResponse { /** @var \Guanguans\LaravelApiResponse\ApiResponse $apiResponse */ // $apiResponse = ApiResponseFacade::getFacadeRoot(); // $apiResponse = resolve(ApiResponseContract::class); // $apiResponse = app(ApiResponseContract::class); $apiResponse = $this->apiResponse(); return $apiResponse->success($data); } public function exampleMethods(): JsonResponse { // return $this->apiResponse()->error($message); // return $this->apiResponse()->exception($exception); return $this->apiResponse()->success($data); } /** * @response * * ```json * { * "status": false, * "code": 500, * "message": "This is a runtime exception.", * "data": {}, * "error": { * "message": "This is a runtime exception.", * "exception": "RuntimeException", * ... * "trace": [ * ... * ] * } * } * ``` */ public function exceptionHandler(): JsonResponse { config()->set('app.debug', true); throw new \RuntimeException('This is a runtime exception.'); } } ```默认响应结构
详情
```json { "status": "boolean", "code": "integer", "message": "string", "data": "mixed", "error": "object" } ```默认响应示例
model
```php with(['country', 'posts'])->first(); return $this->apiResponse()->success($user); } } ``` ```json { "status": true, "code": 200, "message": "OK", "data": { "id": 1, "name": "John", "country_id": 1, "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01", "country": { "id": 1, "name": "China", "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01" }, "posts": [ { "id": 1, "title": "PHP is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01" }, { "id": 2, "title": "JAVA is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:02", "updated_at": "2024-01-01 00:00:02" }, { "id": 3, "title": "Python is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:03", "updated_at": "2024-01-01 00:00:03" } ] }, "error": {} } ```eloquent collection
```php with(['country', 'posts'])->get(); return $this->apiResponse()->success($users); } } ``` ```json { "status": true, "code": 200, "message": "OK", "data": [ { "id": 1, "name": "John", "country_id": 1, "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01", "country": { "id": 1, "name": "China", "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01" }, "posts": [ { "id": 1, "title": "PHP is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01" }, { "id": 2, "title": "JAVA is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:02", "updated_at": "2024-01-01 00:00:02" }, { "id": 3, "title": "Python is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:03", "updated_at": "2024-01-01 00:00:03" } ] }, { "id": 2, "name": "Tom", "country_id": 2, "created_at": "2024-01-01 00:00:02", "updated_at": "2024-01-01 00:00:02", "country": { "id": 2, "name": "USA", "created_at": "2024-01-01 00:00:02", "updated_at": "2024-01-01 00:00:02" }, "posts": [ { "id": 4, "title": "Go is the best language!", "user_id": 2, "created_at": "2024-01-01 00:00:04", "updated_at": "2024-01-01 00:00:04" }, { "id": 5, "title": "JavaScript is the best language!", "user_id": 2, "created_at": "2024-01-01 00:00:05", "updated_at": "2024-01-01 00:00:05" }, { "id": 6, "title": "Ruby is the best language!", "user_id": 2, "created_at": "2024-01-01 00:00:06", "updated_at": "2024-01-01 00:00:06" } ] }, { "id": 3, "name": "Jerry", "country_id": 3, "created_at": "2024-01-01 00:00:03", "updated_at": "2024-01-01 00:00:03", "country": { "id": 3, "name": "Japan", "created_at": "2024-01-01 00:00:03", "updated_at": "2024-01-01 00:00:03" }, "posts": [ { "id": 7, "title": "C is the best language!", "user_id": 3, "created_at": "2024-01-01 00:00:07", "updated_at": "2024-01-01 00:00:07" } ] }, { "id": 4, "name": "Jack", "country_id": 4, "created_at": "2024-01-01 00:00:04", "updated_at": "2024-01-01 00:00:04", "country": { "id": 4, "name": "Korea", "created_at": "2024-01-01 00:00:04", "updated_at": "2024-01-01 00:00:04" }, "posts": [] }, { "id": 5, "name": "Rose", "country_id": 5, "created_at": "2024-01-01 00:00:05", "updated_at": "2024-01-01 00:00:05", "country": { "id": 5, "name": "UK", "created_at": "2024-01-01 00:00:05", "updated_at": "2024-01-01 00:00:05" }, "posts": [] }, { "id": 6, "name": "Lucy", "country_id": 6, "created_at": "2024-01-01 00:00:06", "updated_at": "2024-01-01 00:00:06", "country": { "id": 6, "name": "France", "created_at": "2024-01-01 00:00:06", "updated_at": "2024-01-01 00:00:06" }, "posts": [] }, { "id": 7, "name": "Lily", "country_id": 7, "created_at": "2024-01-01 00:00:07", "updated_at": "2024-01-01 00:00:07", "country": { "id": 7, "name": "Germany", "created_at": "2024-01-01 00:00:07", "updated_at": "2024-01-01 00:00:07" }, "posts": [] } ], "error": {} } ```simple paginate
```php with(['country', 'posts'])->simplePaginate(3); return $this->apiResponse()->success($simplePaginate); } } ``` ```json { "status": true, "code": 200, "message": "OK", "data": { "data": [ { "id": 1, "name": "John", "country_id": 1, "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01", "country": { "id": 1, "name": "China", "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01" }, "posts": [ { "id": 1, "title": "PHP is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01" }, { "id": 2, "title": "JAVA is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:02", "updated_at": "2024-01-01 00:00:02" }, { "id": 3, "title": "Python is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:03", "updated_at": "2024-01-01 00:00:03" } ] }, { "id": 2, "name": "Tom", "country_id": 2, "created_at": "2024-01-01 00:00:02", "updated_at": "2024-01-01 00:00:02", "country": { "id": 2, "name": "USA", "created_at": "2024-01-01 00:00:02", "updated_at": "2024-01-01 00:00:02" }, "posts": [ { "id": 4, "title": "Go is the best language!", "user_id": 2, "created_at": "2024-01-01 00:00:04", "updated_at": "2024-01-01 00:00:04" }, { "id": 5, "title": "JavaScript is the best language!", "user_id": 2, "created_at": "2024-01-01 00:00:05", "updated_at": "2024-01-01 00:00:05" }, { "id": 6, "title": "Ruby is the best language!", "user_id": 2, "created_at": "2024-01-01 00:00:06", "updated_at": "2024-01-01 00:00:06" } ] }, { "id": 3, "name": "Jerry", "country_id": 3, "created_at": "2024-01-01 00:00:03", "updated_at": "2024-01-01 00:00:03", "country": { "id": 3, "name": "Japan", "created_at": "2024-01-01 00:00:03", "updated_at": "2024-01-01 00:00:03" }, "posts": [ { "id": 7, "title": "C is the best language!", "user_id": 3, "created_at": "2024-01-01 00:00:07", "updated_at": "2024-01-01 00:00:07" } ] } ], "links": { "first": "http:\/\/localhost?page=1", "last": null, "prev": null, "next": "http:\/\/localhost?page=2" }, "meta": { "current_page": 1, "from": 1, "path": "http:\/\/localhost", "per_page": 3, "to": 3 } }, "error": {} } ```resource
```php with(['country', 'posts'])->first()); return $this->apiResponse()->success($userResource); } } ``` ```json { "status": true, "code": 200, "message": "OK", "data": { "id": 1, "name": "John", "country_id": 1, "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01", "country": { "id": 1, "name": "China", "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01" }, "posts": [ { "id": 1, "title": "PHP is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01" }, { "id": 2, "title": "JAVA is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:02", "updated_at": "2024-01-01 00:00:02" }, { "id": 3, "title": "Python is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:03", "updated_at": "2024-01-01 00:00:03" } ] }, "error": {} } ```resource collection
```php with(['country', 'posts'])->get()); return $this->apiResponse()->success($userCollection); } } ``` ```json { "status": true, "code": 200, "message": "OK", "data": { "data": [ { "id": 1, "name": "John", "country_id": 1, "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01", "country": { "id": 1, "name": "China", "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01" }, "posts": [ { "id": 1, "title": "PHP is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:01", "updated_at": "2024-01-01 00:00:01" }, { "id": 2, "title": "JAVA is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:02", "updated_at": "2024-01-01 00:00:02" }, { "id": 3, "title": "Python is the best language!", "user_id": 1, "created_at": "2024-01-01 00:00:03", "updated_at": "2024-01-01 00:00:03" } ] }, { "id": 2, "name": "Tom", "country_id": 2, "created_at": "2024-01-01 00:00:02", "updated_at": "2024-01-01 00:00:02", "country": { "id": 2, "name": "USA", "created_at": "2024-01-01 00:00:02", "updated_at": "2024-01-01 00:00:02" }, "posts": [ { "id": 4, "title": "Go is the best language!", "user_id": 2, "created_at": "2024-01-01 00:00:04", "updated_at": "2024-01-01 00:00:04" }, { "id": 5, "title": "JavaScript is the best language!", "user_id": 2, "created_at": "2024-01-01 00:00:05", "updated_at": "2024-01-01 00:00:05" }, { "id": 6, "title": "Ruby is the best language!", "user_id": 2, "created_at": "2024-01-01 00:00:06", "updated_at": "2024-01-01 00:00:06" } ] }, { "id": 3, "name": "Jerry", "country_id": 3, "created_at": "2024-01-01 00:00:03", "updated_at": "2024-01-01 00:00:03", "country": { "id": 3, "name": "Japan", "created_at": "2024-01-01 00:00:03", "updated_at": "2024-01-01 00:00:03" }, "posts": [ { "id": 7, "title": "C is the best language!", "user_id": 3, "created_at": "2024-01-01 00:00:07", "updated_at": "2024-01-01 00:00:07" } ] }, { "id": 4, "name": "Jack", "country_id": 4, "created_at": "2024-01-01 00:00:04", "updated_at": "2024-01-01 00:00:04", "country": { "id": 4, "name": "Korea", "created_at": "2024-01-01 00:00:04", "updated_at": "2024-01-01 00:00:04" }, "posts": [] }, { "id": 5, "name": "Rose", "country_id": 5, "created_at": "2024-01-01 00:00:05", "updated_at": "2024-01-01 00:00:05", "country": { "id": 5, "name": "UK", "created_at": "2024-01-01 00:00:05", "updated_at": "2024-01-01 00:00:05" }, "posts": [] }, { "id": 6, "name": "Lucy", "country_id": 6, "created_at": "2024-01-01 00:00:06", "updated_at": "2024-01-01 00:00:06", "country": { "id": 6, "name": "France", "created_at": "2024-01-01 00:00:06", "updated_at": "2024-01-01 00:00:06" }, "posts": [] }, { "id": 7, "name": "Lily", "country_id": 7, "created_at": "2024-01-01 00:00:07", "updated_at": "2024-01-01 00:00:07", "country": { "id": 7, "name": "Germany", "created_at": "2024-01-01 00:00:07", "updated_at": "2024-01-01 00:00:07" }, "posts": [] } ] }, "error": {} } ```error
```php apiResponse()->error('This is an error.'); } } ``` ```json { "status": false, "code": 400, "message": "This is an error.", "data": {}, "error": {} } ```exception
```php set('app.debug', false); $runtimeException = new \RuntimeException('This is a runtime exception.'); return $this->apiResponse()->exception($runtimeException); } } ``` ```json { "status": false, "code": 500, "message": "Internal Server Error", "data": {}, "error": { "message": "Server Error" } } ```debug exception
```php set('app.debug', true); $runtimeException = new \RuntimeException('This is a runtime exception.'); return $this->apiResponse()->exception($runtimeException); } } ``` ```json { "status": false, "code": 500, "message": "This is a runtime exception.", "data": {}, "error": { "message": "This is a runtime exception.", "exception": "RuntimeException", "file": "\/tests\/Feature\/ExceptionDataTypesTest.php", "line": 45, "trace": [ { "function": "{closure}", "class": "P\\Tests\\Feature\\ExceptionDataTypesTest", "type": "->" }, { "file": "\/vendor\/pestphp\/pest\/src\/Factories\/TestCaseFactory.php", "line": 151, "function": "call_user_func" }, { "function": "Pest\\Factories\\{closure}", "class": "P\\Tests\\Feature\\ExceptionDataTypesTest", "type": "->" }, { "file": "\/vendor\/pestphp\/pest\/src\/Concerns\/Testable.php", "line": 301, "function": "call_user_func_array" }, { "file": "\/vendor\/pestphp\/pest\/src\/Support\/ExceptionTrace.php", "line": 29, "function": "Pest\\Concerns\\{closure}", "class": "P\\Tests\\Feature\\ExceptionDataTypesTest", "type": "->" }, { "file": "\/vendor\/pestphp\/pest\/src\/Concerns\/Testable.php", "line": 302, "function": "ensure", "class": "Pest\\Support\\ExceptionTrace", "type": "::" }, { "file": "\/vendor\/pestphp\/pest\/src\/Concerns\/Testable.php", "line": 278, "function": "__callClosure", "class": "P\\Tests\\Feature\\ExceptionDataTypesTest", "type": "->" }, { "file": "\/vendor\/phpunit\/phpunit\/src\/Framework\/TestCase.php", "line": 1617, "function": "__test", "class": "P\\Tests\\Feature\\ExceptionDataTypesTest", "type": "->" }, { "file": "\/vendor\/phpunit\/phpunit\/src\/Framework\/TestCase.php", "line": 1223, "function": "runTest", "class": "PHPUnit\\Framework\\TestCase", "type": "->" }, { "file": "\/vendor\/phpunit\/phpunit\/src\/Framework\/TestResult.php", "line": 729, "function": "runBare", "class": "PHPUnit\\Framework\\TestCase", "type": "->" }, { "file": "\/vendor\/phpunit\/phpunit\/src\/Framework\/TestCase.php", "line": 973, "function": "run", "class": "PHPUnit\\Framework\\TestResult", "type": "->" }, { "file": "\/vendor\/phpunit\/phpunit\/src\/Framework\/TestSuite.php", "line": 685, "function": "run", "class": "PHPUnit\\Framework\\TestCase", "type": "->" }, { "file": "\/vendor\/phpunit\/phpunit\/src\/Framework\/TestSuite.php", "line": 685, "function": "run", "class": "PHPUnit\\Framework\\TestSuite", "type": "->" }, { "file": "\/vendor\/phpunit\/phpunit\/src\/TextUI\/TestRunner.php", "line": 651, "function": "run", "class": "PHPUnit\\Framework\\TestSuite", "type": "->" }, { "file": "\/vendor\/phpunit\/phpunit\/src\/TextUI\/Command.php", "line": 146, "function": "run", "class": "PHPUnit\\TextUI\\TestRunner", "type": "->" }, { "file": "\/vendor\/pestphp\/pest\/src\/Console\/Command.php", "line": 119, "function": "run", "class": "PHPUnit\\TextUI\\Command", "type": "->" }, { "file": "\/vendor\/pestphp\/pest\/bin\/pest", "line": 61, "function": "run", "class": "Pest\\Console\\Command", "type": "->" }, { "file": "\/vendor\/pestphp\/pest\/bin\/pest", "line": 62, "function": "{closure}" }, { "file": "\/vendor\/bin\/pest", "line": 115, "function": "include" } ] } } ```exception handler
```php middleware(SetAcceptHeader::class)->only('example'); } public function example(): JsonResponse { config()->set('app.debug', false); throw new \RuntimeException('This is a runtime exception.'); } } ``` ```json { "status": false, "code": 500, "message": "Internal Server Error", "data": {}, "error": { "message": "Server Error" } } ```locale exception
```php set('app.debug', false); config()->set('app.locale', 'zh_CN'); $runtimeException = new \RuntimeException('This is a runtime exception.'); return $this->apiResponse()->exception($runtimeException); } } ``` ```json { "status": false, "code": 500, "message": "内部服务器错误", "data": {}, "error": { "message": "Server Error" } } ```更多例子...
* [功能测试](https://github.com/guanguans/laravel-api-response/tree/main/tests/Feature) * [示例结果](https://github.com/guanguans/laravel-api-response/tree/main/tests/__snapshots__)FAQ
如何自定义管道
* 参考 [Pipes](https://github.com/guanguans/laravel-api-response/tree/main/src/Pipes) * 简单示例: ```php如何自定义异常管道
* 参考 [ExceptionPipes](https://github.com/guanguans/laravel-api-response/tree/main/src/ExceptionPipes)如何在单个 api 中自定义管道
* 参考 [HasPipes.php](https://github.com/guanguans/laravel-api-response/tree/main/src/Concerns/HasPipes.php)、[HasExceptionPipes.php](https://github.com/guanguans/laravel-api-response/tree/main/src/Concerns/HasExceptionPipes.php) * 简单示例: ```php apiResponse() // ->unshiftPipes(...) ->pushPipes( static function (array $data, \Closure $next): JsonResponse { if ($data['data'] instanceof \iterable) { $data['data'] = iterator_to_array($data['data']); } return $next($data); } ) // ->unshiftExceptionPipes(...) // ->pushExceptionPipes(...) ->success($iterator); } } ```如何始终以成功的 http 状态代码进行响应
* 参考 [StatusCodePipe.php](https://github.com/guanguans/laravel-api-response/tree/main/src/Pipes/StatusCodePipe.php) * 删除该配置 `api-response.pipes.StatusCodePipe`如何本地化消息
* 参考 [MessagePipe.php](https://github.com/guanguans/laravel-api-response/tree/main/src/Pipes/MessagePipe.php) * 安装 [Laravel-Lang/http-statuses](https://github.com/Laravel-Lang/http-statuses) `composer require --dev laravel-lang/http-statuses` 或创建语言文件 `resources/lang/***/http-statuses.php`http 状态的快捷方法
* 参考 [ConcreteHttpStatus.php](https://github.com/guanguans/laravel-api-response/tree/main/src/Concerns/ConcreteHttpStatus.php)参考项目
原文连接