使用 Laravel 开发 API,参考了网上一些资料,laravel 默认已经支持了 API 开发,但是因为都没有了解过,打算尝试使用 Dingo API

github 地址:
	https://github.com/dingo/api

laravel-china 中文文档:
	https://laravel-china.org/docs/dingo-api/2.0.0

文档写的非常详细,翻译的也非常好,但是需要仔细品读,另外 Dingo API 中使用到了其他两个技术,也需要了解下。之前已经写过笔记了,可参考:
	fractal - https://blog.csdn.net/beyond__devil/article/details/83870176

	jwt-auth - https://blog.csdn.net/beyond__devil/article/details/83827075

这里简单挑几个重点写下:
	1.安装
		composer require dingo/api

		发布配置
			php artisan vendor:publish --provider="Dingo\Api\Provider\LaravelServiceProvider"

		Facades
			Dingo\Api\Facade\API
			Dingo\Api\Facade\Route

	2.配置信息

	3.创建端点(在 API 中,路由一般叫做端点)
		1)引用 Dingo API
			$api = app('Dingo\Api\Routing\Router');

		2)设置版本分组

			// 单个分组
			$api->version('v1', function($api){

			})

			// 多个分组
			$api->version(['v1', 'v2'], function($api){

			})

			// 第二个参数,还可以传递一个 『属性数组』
			$api->version(['v1', 'v2'], ['middleware' => 'foo'], function($api){

			})
			注意:
				属性数组,是旧版的 Laravel,5.7 版本有些可能不支持

			// 其他的和 laravel 的路由没有太大的区分(旧版,新版链式调用不支持)
			$api->version('v1', function($api){
				$api->group(['middleware' => 'bar'], function($api){
					...
				});
			})

		3)创建端点(之前大概看了点源码,忘记了,下面是之前笔记的)
			group() - 路由分组
			domain() - 子域名路由
			namespace() - 命名空间
			prefix() - 前缀
			name() - 命名前缀,是 as 的别名
			as() - 命名前缀
			middle() - 中间件
			where() - 参数的正则约束

			/*
				5.7 版本,可以使用这些方法,之前的版本,没有这些方法,使用的是:
					group(['prefix' => '', 'namespace' => '', ...], function(){

					});
			 */

		4)命名路由 & 生成路由
			$api->get('users/{id}', ['as' => 'users.index', 'uses' => 'Api\V1\UserController@show']);

			app('Dingo\Api\Routing\UrlGenerator')->version('v1')->route('users.index');

		5)命令行中查看路由
			php artisan api::routes

		注意:
			Laravel 5.7版本,routes/api.php 默认就具备中间件,我们需考虑使用 'Dingo API' 还是 'Laravel 系统默认'

			app/Providers/RouteServiceProvider.php 
		        Route::prefix('api')
		             ->middleware('api')
		             ->namespace($this->namespace)
		             ->group(base_path('routes/api.php'));

		    注意:
		    	如果采用 Ding API,我们可能得取消这里默认的 prefix、middleware、namespace


	4.响应
		响应生成器,需要使用 'Dingo\Api\Routing\Helpers' trait。我们的 API 控制器基本都要使用它,所以创建一个 『基类控制器』
			php artisan make:controller Api/Controller

			<?php

			namespace App\Http\Controllers\Api;

			use Illuminate\Http\Request;
			use Dingo\Api\Routing\Helpers;
			use App\Http\Controllers\Controller as BaseController;

			class Controller extends BaseController
			{
			    use Helpers;
			}

		关于响应生成器,文档写的很详细,上次可能看了下源码,总结了下,基本和文档一致。	
		参考源码:Dingo\Api\Http\Response\Factory

			1)响应数组
				$user = User::findOrFail($id);
				$this->response->array($user->toArray());		// 估计只能是数组

				// 查看源码:
				// 	 array 时,会响应 $parameters[0] 
				//	『new Response($parameters[0])』

			2)响应一个元素
				$user = User::findOrFail($id);
				$this->response->item($user, new UserTransformer)

			3)响应一个元素集合
				$users = User::all();
				$this->response->collection($user, new UserTransformer)

			4)分页响应
				$users = User::paginate(25);
				$this->response->paginator($user, new UserTransformer)

			5)无内容响应
				$this->response->noContent();
		
			6)创建了资源的响应
				$this->response->created($location = null, $content = null);
				location - 会在 header 添加 Location 头部
				content - 响应内容

			7)accepted() - 同 created() 一样,created() 返回 201,accepted() 返回 202

			8)自定义错误内容和状态码
				error($message, $statusCode)

			9)其他调用 error() 的便捷方法
				errorNotFound() - 404
				errorBadRequest() - 400
				errorForbidden() - 403
				errorInternal() - 500
				errorUnauthorized() - 401
				errorMethodNotAllowed() - 405

			10)添加额外的头信息
				->withHeader('X-Foo', 'Bar')

			11)添加 Meta 信息
				->addMeta('foo', 'bar')->addMeta(xx, yy)

				->setMeta($meta)

			12)设置响应状态码
				->setStatusCode(200)

		事件:
			返回响应之前,会转换响应,如果响应的变化有更多的控制,可以使用以下2个事件
				ResponseWasMorphed
				ResponseIsMorphing

	5.异常处理
		API 的开发过程中,对于异常,我们采用直接 throw,然后统一由 Dingo API 来捕获,统一处理

		Symfony 内置的异常

		Dingo API 内置的资源异常

		自定义异常
			继承 Symfony\Component\HttpKernel\Exception\HttpException
			或
			实现 Symfony\Component\HttpKernel\Exception\HttpExceptionInterface

		自定义异常响应
			app('Dingo\Api\Exception\Handler')->register(function (Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException $exception) {
			    return Response::make(['error' => 'Hey, 你这是要干嘛!?'], 401);
			});

		表单请求
			定义基础的 API 表单请求类,验证失败,将抛出:
				Dingo\Api\Exception\ValidationHttpException

		Dingo API 默认的错误格式
		    'errorFormat' => [
		        'message' => ':message',
		        'errors' => ':errors',
		        'code' => ':code',
		        'status_code' => ':status_code',
		        'debug' => ':debug',
		    ],

	6.Transformers
		使用 transformers 有 2 种方法:
			1>为一个指定的类注册一个 transformer,直接从路由中返回这个类,并且通过 transformer 自动运行
				app('Dingo\Api\Transformer\Factory')->register('User', 'UserTransformer');

			2>使用响应生成器

		Fractal
			Fractal 是 Dingo API 使用的默认转换层

			自动关系预加载

			更多配置
				定义嵌入关系时,要自定义 'include' 关键词和 '分隔符',在 'service provider' 或 '启动文件' 中,手动实例化 'Dingo\Api\Transformer\Adapter\Fractal'
					$this->app['Dingo\Api\Transformer\Factory']->setAdapter(function ($app) {

						// 这里是 'include' 和 ','
					    return new Dingo\Api\Transformer\Adapter\Fractal(new League\Fractal\Manager, 'include', ',');
					});

			响应生成器的高级用法
				响应生成器的 item()、collection() 和 paginator() 方法,接受额外参数,进一步自定义 Fractal

				第三个参数 - 资源键	
					return $this->item($user, new UserTransformer, ['key' => 'user']);

				第四个参数 - 回调函数
					return $this->collection($users, new UserTransformer, [], function ($resource, $fractal) {
					    $resource->setCursor($cursor);
					});

					回调函数有 2 个参数:
						第一个参数:
							League\Fractal\Resource\Item 或 League\Fractal\Resource\Collection 实例
						第二个参数:
							League\Fractal\Manager 实例

				不使用 '第三个参数',也可以省略,直接传递 '第四个参数' 回调函数

		自定义转换层

	7.API 认证
		配置身份验证提供者
			内置 3 个身份验证提供者:
				HTTP Basic - Dingo\Api\Auth\Provider\Basic
				JSON Web Tokens - Dingo\Api\Auth\Provider\JWT
				OAuth 2.0 - Dingo\Api\Auth\Provider\OAuth2

			默认仅在配置文件中,启用 HTTP 基本身份验证

			HTTP 基本验证
				服务提供者使用 laravel 内置的默认基本身份验证。需要在 '配置文件' 或 '引导文件' 配置此服务提供者
					app('Dingo\Api\Auth\Auth')->extend('basic', function ($app) {
					  	return new Dingo\Api\Auth\Provider\Basic($app['auth'], 'email');
					});

			JSON Web Tokens(JWT)
				使用 tymon/jwt-auth 包

				在 '配置文件' 或 '引导文件' 中配置该服务提供者
					config.php
						'auth' => [
						    'jwt' => 'Dingo\Api\Auth\Provider\JWT',
						],

					app('Dingo\Api\Auth\Auth')->extend('jwt', function ($app) {
					   return new Dingo\Api\Auth\Provider\JWT($app['Tymon\JWTAuth\JWTAuth']);
					});

			OAuth 2.0
				使用 league/oauth2-server 或 lucadegasperi/oauth2-server-laravel 包

				需要配置 'provider server - 服务提供者' 或 'bootstrap - 引导文件'(包没有给我们提供 服务提供者,而 basic 和 jwt 都有默认的服务提供者,应该是这样...)

				同时,应该还需要配置 config.php 的 auth

		自定义身份验证

		保护级别
			可以使用 'api.auth' 中间件来验证

			// 某个版本路由
			$api->version(['middleware' => 'api.auth'], function(){});

			// 路由组
			$api->group( ['middleware' => 'api.auth'], function(){});

			// 单个路由
			$api->get('user', ['middleware' => 'api.auth'], function(){});

			控制器中
				$this->middleware('api.auth', ['only' => ['index']]);

			只允许特定的身份验证提供者
				$api->version(['middleware' => 'api.auth', 'providers' => ['basic', 'oauth']], function(){});

		检索经过身份验证的用户
			$user = app('Dingo\Api\Auth\Auth')->user();

			如果控制器中,使用了 'Dingo\Api\Routing\Helpers',可以使用 $this->auth 属性

			use Dingo\Api\Routing\Helpers;		// 引入 trait

			class UserController extends Controller
			{
				use Helpers;		// 使用 trait

				public function index()	
				{
					$user = $this->auth->user();
					return $user;
				}
			}

		不通过中间件来验证,需要手动在需要的地方进行验证
			if( !app('Dingo\Api\Auth\Auth')->user()){
				return '用户未验证!';
			}

	8.访问节流限制(rate limiting)
		改变节流限速的 key
			默认是 "客户端IP",通过 $request->getClientIp() 获取。
			我们可以自定义:
				app('Dingo\Api\Http\RateLimit\Handler')->setRateLimiter(function ($app, $request) {
				    return $app['example']->getRateLimiterKey();
				});

				回调函数的 2 个参数是:
					$app - Ioc 容器
					$request - 请求实例

		启用节流限速
			使用 'api.throttle' 中间件
			支持,额外的 2 个选项:
				'middleware' => 'api.throttle', 'limit' => 100, 'expires' => 5
				limit - 限制次数
				expires - 过期时间

		自定义阀门(throttle)
			继承 Dingo\Api\Contract\Http\RateLimit\Throttle,定义一个 match() 方法,返回 true | false
				use Illuminate\Container\Container;
				use Dingo\Api\Http\RateLimit\Throttle\Throttle;

				class CustomThrottle extends Throttle
				{
				    public function match(Container $app)
				    {
				        // 在这里执行一些逻辑并根据是否返回 true 或 false
				        // 你的条件与阀门匹配。
				    }
				}

			注册阀门
				api.php
				'throttling' => [
				    'custom' => new CustomThrottle(['limit' => 200, 'expires' => 10])
				]

	9.内部调用
		API 都是外部调用的,但是如果内部某个方法内,也想调用 API 的结果,这样可复用代码

			// 构建一个分发器
			$dispatcher = app('Dingo\Api\Dispatcher');
			// 发起内部请求
			$users = $dispatcher->get('api/users');

		控制器中,也可使用 'Dingo\Api\Routing\Helpers' trait
			use Dingo\Api\Routing\Helpers;		// 引用 trait
			class HomeController extends Controller
			{
			    use Helpers;		// 使用 trait

			    public function index()
			    {
			        $users = $this->api->get('users');		// 调用内部请求

			        return view('index')->with('users', $users);
			    }
			}

		发送数据
			$dispatcher->with(['name' => 'Jason', 'location' => 'Australia'])->post('users');
			或
			$dispatcher->post('users', ['name' => 'Jason', 'location' => 'Australia']);

		指定版本的 API
			$dispatcher->version('v2')->get('users');

		指定的域名
			$dispatcher->on('api.example.com')->get('users');

		上传附件
			1>Symfony\Component\HttpFoundation\File\UploadedFile 实例数组
				$dispatcher->attach(Input::files())->post('photos');

			2>文件路径数组,数组 key 是文件的下标
				$dispatcher->attach(['photo' => 'photos/me.jpg'])->post('photos');

			3>文件路径相关的元数据数组(上传时,不会再计算文件 mime 类型和文件大小)
				dispatcher->attach([
				    'photo' => [
				        'path' => 'photos/me.jpg',
				        'mime' => 'image/jpeg',
				        'size' => '49430'
				    ]
				])->post('photos');

		发送 JSON 数据
			$data = ['name' => 'bill', 'password' => 12345];
			$dispatcher->json($data)->post('users');
			注意:
				如果 $data 是一个数组,将会自动被转换为 json。
				这个请求的 Content-Type 被设置为 application/json

		模拟认证用户
			当我们请求的端点(路由),需要用户认证通过后,才可进行处理,模拟用户

			任何后续请求都将视为同一用户
				$dispatcher->be(auth()->user())->get('posts');

			只为给定的用户模拟一次请求
				$dispatcher->be(auth()->user())->once()->get('posts');

		获取原始返回对象

			// 默认的 API 请求,返回的数据是经过预先转换、格式化
			$response = $dispatcher->get('users');

			// 要想获取原始查询的数据,添加 raw()
			$response = $dispatcher->raw()->get('users');

		异常处理
			内部调用的 API,会抛出异常,我们如果想处理异常,需要自己捕获。
			捕获的异常类需要和抛出的异常类一致

	10.OAuth 2.0 认证
		Scopes

	11.请求你的 API
		使用 Postman 

		使用 CURL
			curl -v -H "Accept: application/vnd.YOUR_SUBTYPE.v1+json" http://example.app/users

	12.API 文档
		资源
			/**
			 * 用户资源标识
			 *
			 * @Resource("Users", uri="/users")
			 */

		行为
			@Get、@Post、@Put、@Patch、@Delete
			@Versions
			@Request
			@Response
			@Transaction
			@Parameters


	13.命令行工具
		1>生成 API 路由列表
			php artisan api:routes
			php artisan api:routes --versions v1
			php artisan api:routes --scopes read_user_data --scopes write_user_data

		2>缓存 API 路由,同时缓存主路由。
			php artisan api:cache
			切记:
				不要执行 laravel 的 route:cache,这样只会缓存主路由,不会缓存 Dingo API 的路由

		3>根据标准注释,生成 API 文档
			php artisan api:docs
			php artisan api:docs --name Example --use-version v2 --output-file /path/to/documentation.md
			php artisan api:docs --name Example --use-version v2 > /path/to/documentation.md 		// 或使用 '>' 标准输出重定向


 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐