使用 Dingo API 扩展包快速构建 Laravel RESTful API(十一) —— 在应用内部请求 Dingo API

栏目: PHP · 发布时间: 5年前

内容简介:Dingo 扩展包花费了很大的精力来提供从应用内部请求 Dingo API 接口的功能,这意味着,通过 Dingo 扩展包实现的 API 接口不仅可以被客户端和第三方应用消费,还可以为应用内部的 Web 路由和其他 API 路由提供数据和服务支持,这样一来,我们就可以构建一个完全基于 API 驱动的应用,支持内部请求的 API 还有一个好处就是可以返回原生数据对象而不是 HTTP 响应对象,因此,我们可以基于 Laravel 及 Dingo 提供的语法糖来处理返回的结果或者处理抛出的异常。下面我们就来看一下

Dingo 扩展包花费了很大的精力来提供从应用内部请求 Dingo API 接口的功能,这意味着,通过 Dingo 扩展包实现的 API 接口不仅可以被客户端和第三方应用消费,还可以为应用内部的 Web 路由和其他 API 路由提供数据和服务支持,这样一来,我们就可以构建一个完全基于 API 驱动的应用,支持内部请求的 API 还有一个好处就是可以返回原生数据对象而不是 HTTP 响应对象,因此,我们可以基于 Laravel 及 Dingo 提供的语法糖来处理返回的结果或者处理抛出的异常。

下面我们就来看一下如何在 Laravel 应用中通过内部请求消费 Dingo API,要使用内部请求功能,先要获取一个调度器实例:

$dispatcher = app(\Dingo\Api\Dispatcher::class);

快速入门

在 API 路由中请求 API

首先,我们可以在 Dingo API 中消费其它的 API 接口:

$api->version('v3', function ($api) {
    ...
    $api->get('task/{id}', function ($id) {
        $dispatcher = app(\Dingo\Api\Dispatcher::class);
        $task = $dispatcher->version('v1')->get('dingoapi/task/' . $id);
        dd($task);
    });
});

在这个示例中,我们在 Dingo API 的 v3 版本分组中定义一个基于 v1 版本 task/{id} 接口返回数据的路由,在获取到调度器实例后,通过 version 方法指定要消费的 Dingo API 版本,然后通过 get 方法对相应的路由发起 GET 请求返回数据,这样我们就可以获取到对应的任务数据:

使用 Dingo API 扩展包快速构建 Laravel RESTful API(十一) —— 在应用内部请求 Dingo API

在 Web 路由中请求 API

然后,我们可以在 routes/web.php 中定义一个消费上述 Dingo API 的 Web 路由:

$dispatcher = app(\Dingo\Api\Dispatcher::class);
Route::get('/task/{id}', function ($id) use ($dispatcher) {
    $task = $dispatcher->version('v3')->get('dingoapi/task/' . $id);
    dd($task);
});

这次,我们消费的是 v3 版本的 Dingo API 接口,返回数据和上面一样。

内部请求认证 API 接口

在已认证 API 路由中请求

在已认证的 API 路由中请求 Dingo API 的认证接口比较简单,不需要做任何额外的操作,因为已经认证的 API 接口中发起内部请求中会自动带上 Authorization 字段。

在未认证或 Web 路由中请求

在未认证 API 路由或 Web 路由中对 Dingo API 认证接口发起内部请求需要将访问令牌设置到请求头 Authorization 字段中才可以,我们以之前待办任务列表中的 home 路由为例,这是一个 Web 路由,虽然需要认证才能访问,但是 Web 路由认证和 API 路由认证走的是两套体系,之间并不相通,内部请求 的 API 接口需要单独认证,这里我们借助 Passport私人访问令牌来实现该 API 接口的认证,打开 app/Http/Controllers/HomeController.php ,将 index 方法中获取任务列表的逻辑改为基于 Dingo API v3 版本的 tasks.index 接口获取,该接口是需要认证的,我们通过 Passport 私人访问令牌生成访问令牌,然后将其设置到 Authorization 请求头:

public function index(Request $request, Dispatcher $dispatcher)
{
    $params = [];
    if ($request->has('page')) {
        $params['page'] = $request->get('page');
    }
    if ($request->has('limit')) {
        $params['limit'] = $request->get('limit');
    }
    $token = $request->user()->createToken('Internal Request Token')->accessToken;
    $tasks = $dispatcher->on('todo.test')->header('Authorization', 'Bearer ' . $token)->version('v3')->get('dingoapi/tasks', $params);
    return view('home', ['tasks' => json_encode($tasks->items())]);
}

由于 tasks.index API 接口还支持分页数据,我们将相应的参数通过调度器实例的 get 方法的第二个参数传递过去。

接口返回的并不是 HTTP 响应实例,而是包含任务列表和分页信息的分页器实例,通过调用该实例上的 items 方法即可返回任务列表数据。

当然为了让 Passport 私人访问令牌生效,还需要通过如下命令创建对应的数据表记录以便用于生成令牌信息:

php artisan passport:client --personal

如果之前已经运行过相关命令或者 oauth_clients 表中已经存在 Laravel Personal Access Client 记录,也可以直接在 AuthServiceProviderboot 方法中通过 Passport 的 personalAccessClientId 方法直接使用该记录:

public function boot()
{
    ...
    Passport::personalAccessClientId('client-id');
}

client_id 替换成相应的数据库主键 ID 即可。

访问 http://todo.test/home 页面,登录成功之后就可以看到任务列表信息了,和之前返回结果一样:

使用 Dingo API 扩展包快速构建 Laravel RESTful API(十一) —— 在应用内部请求 Dingo API

不同的是现在还支持分页功能,这可以通过在请求参数中设置页码和每页显示数量来实现:

使用 Dingo API 扩展包快速构建 Laravel RESTful API(十一) —— 在应用内部请求 Dingo API

更多特性

以上就已经介绍完最常见的通过 GET 方式对 Dingo API 发起的内部请求,此外,Dingo 调度器还支持很多其他方法,通过这些方法,我们可以实现更多更复杂的内部请求,下面我们就一些常见的场景进行介绍。

发起 POST 请求

除了 GET 请求外, Dispatcher 调度器还支持 POST、PUT、PATCH、DELETE 等其它常见的 HTTP 请求方法,以 POST 请求为例,对应的方法名是 post ,我们可以这样通过 POST 请求发送数据:

$dispatcher->with(['name' => '学院君', 'location' => '杭州'])->post('users');

还可以这样:

$dispatcher->post('users', ['name' => '学院君', 'location' => '杭州']);

PUT、PATCH、DELETE 对应的内部请求发送方式也与 POST 一样,这里就不再赘述,详情请看 vendor/dingo/api/src/Dispatcher.php 源码。

上传文件

Dingo API 调度器提供了多种方式来支持上传文件请求,你可以通过传入 Symfony\Component\HttpFoundation\File\UploadedFile 实例到 attach 方法来添加文件到 POST 请求:

$dispatcher->attach(Input::files())->post('photos');

也可以通过数组方式传入文件标识与路径信息来上传文件:

$dispatcher->attach(['photo' => 'photos/me.jpg'])->post('photos');

这种方式还支持一次上传多个文件以及设置多个文件元信息(这种方式避免了服务端计算文件类型和尺寸):

$dispatcher->attach([
    'photo' => [
        'path' => 'photos/me.jpg',
        'mime' => 'image/jpeg',
        'size' => '49430'
    ]
])->post('photos');

发送 JSON 格式请求数据

还可以通过调度器上的 json 方法发送 JSON 格式请求数据:

$data = ['name' => 'xueyuanjun', 'password' => '12345678'];
$dispatcher->json($data)->post('users');

同时请求头中 Content-Type 字段会被设置为 application/json

获取原生响应对象

内部请求默认返回的是未经转化和格式化的原生数据对象,如果你想要获取响应对象,可以调用 raw 方法实现:

$response = $dispatcher->raw()->get('users');

异常及错误处理

通过内部请求调用 Dingo API 时,所有接口处理过程中抛出的异常都需要手动捕获并处理,比如 Api\TaskControllerstore 方法抛出冲突异常:

use Symfony\Component\HttpKernel\Exception\ConflictHttpException;

public function store(CreateTaskRequest $request)
{
    throw new ConflictHttpException('we got a conflict!');
}

如果对该方法对应 API 路由发起内部请求,则需要手动捕获抛出的异常:

try {
    app(\Dingo\Api\Dispatcher::class)->with($payload)->post('dingoapi/tasks');
} catch (Symfony\Component\HttpKernel\Exception\ConflictHttpException $e) {
    // Do something here, like return with an error.
}

如果某个 API 接口返回的是错误响应,比如 show 方法这样:

public function show($id)
{
    if (!is_numeric($id)) {
        return $this->response->errorBadRequest();
    }
    $task = Task::find($id);
    if (!$task) {
        return $this->response->errorNotFound();
    }
    ...
}

则在对其发起内部请求的时候,需要捕获 Dingo\Api\Exception\InternalHttpException 异常:

try {
    $task = $dispatcher->version('v3')->get('dingoapi/tasks/' . $id);
} catch (\Dingo\Api\Exception\InternalHttpException $exception) {
    return $exception->getResponse();
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

颠覆医疗

颠覆医疗

[美]埃里克·托普 / 张南、魏薇、何雨师 / 译言·东西文库/电子工业出版社 / 2014-1-20 / 55.00

“创造性破坏”是奥地利经济学家约瑟夫·熊彼特最著名的理论,当一个产业在革新之时,都需要大规模地淘汰旧的技术与生产体系,并建立起新的生产体系。电器之于火器、汽车之于马车、个人计算机之于照排系统,都是一次又一次的“创造性破坏”,旧的体系完全不复存在,新的体系随之取代。 “创造性破坏”已经深深地改变了我们的生活,在这个数字时代,我们身边的一切都被“数字化”了。只有一处,也许是由于其本身的根深蒂固,......一起来看看 《颠覆医疗》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具