Menu

2.4. 响应

一个可用的 API 简单来说就是通过接受请求并将易处理的响应返回给客户端,一般来说, API 有多种易处理的方式返回响应,例如 JSON ,而具体应该使用哪种方式返回响应取决于你的 API 的复杂程度。

通常来说,直接在控制器中返回一个数组或对象就是最简单的返回响应的方式,但是不是所有的对象都能被正确的格式化,所以需要确认该对象实现了 ArrayObjectIlluminate\Support\Contracts\ArrayableInterface 接口。

class UserController
{
    public function index()
    {
        return User::all();
    }
}

在这个例子里,我们的 User 类继承了 Illuminate\Database\Eloquent\Model, 这意味着它能被格式化成数组,所以我们可以直接返回 users 的集合,通过调用 User::all()。同样的, 你可以返回一个单一的用户。

class UserController
{
    public function show($id)
    {
        return User::findOrFail($id);
    }
}

这个包将会自动的格式化响应为 JSON,并设置 Content-Type 头为 application/json

响应生成器

响应生成器提供了一个流畅的接口去方便的建立一个更定制化的响应。响应的生成器通常是与 transformer 相结合。

要利用响应生成器, 你的控制器需要使用 Dingo\Api\Routing\Helpers trait。为了在你的控制器里保持引入和使用这个 trait,你可以创建一个基础控制器,然后你的所有的 API 控制器都继承它。

use Dingo\Api\Routing\Helpers;
use Illuminate\Routing\Controller;

class BaseController extends Controller
{
    use Helpers;
}

现在你的控制器可以直接继承基础控制器。响应生成器可以在控制器里通过 $response 属性获取。提示,下面所有的方法也可以当做 withX 使用,你应该会更喜欢这种语法。

下面的一些文档利用了 Transformers,请务必阅读这一章了解更多详情。

响应一个数组

class UserController extends BaseController
{
    public function show($id)
    {
        $user = User::findOrFail($id);

        return $this->response->array($user->toArray());
    }
}

响应一个元素

class UserController extends BaseController
{
    public function show($id)
    {
        $user = User::findOrFail($id);

        return $this->response->item($user, new UserTransformer);
    }
}

响应一个元素集合

class UserController extends BaseController
{
    public function index()
    {
        $users = User::all();

        return $this->response->collection($users, new UserTransformer);
    }
}

分页响应

class UserController extends BaseController
{
    public function index()
    {
        $users = User::paginate(25);

        return $this->response->paginator($users, new UserTransformer);
    }
}

无内容响应

return $this->response->noContent();

创建了资源的响应

return $this->response->created();

你可以在第一个参数的位置,提供创建的资源的位置。

return $this->response->created($location);

错误响应

这有很多不同的方式创建错误响应,你可以快速的生成一个错误响应。

// 一个自定义消息和状态码的普通错误。
return $this->response->error('This is an error.', 404);

// 一个没有找到资源的错误,第一个参数可以传递自定义消息。
return $this->response->errorNotFound();

// 一个 bad request 错误,第一个参数可以传递自定义消息。
return $this->response->errorBadRequest();

// 一个服务器拒绝错误,第一个参数可以传递自定义消息。
return $this->response->errorForbidden();

// 一个内部错误,第一个参数可以传递自定义消息。
return $this->response->errorInternal();

// 一个未认证错误,第一个参数可以传递自定义消息。
return $this->response->errorUnauthorized();

添加额外的头信息

一旦你已经使用了上面的方法,你就可以自己添加额外的头信息

return $this->response->item($user, new UserTransformer)->withHeader('X-Foo', 'Bar');

添加 Meta 信息

一些数据转换层也许利用了 meta 数据。当你需要提供链接资源的额外数据这将会很有用。

return $this->response->item($user, new UserTransformer)->addMeta('foo', 'bar');

您还可以设置元数据数组,而不是链接多个方法调用。

return $this->response->item($user, new UserTransformer)->setMeta($meta);

设置响应状态码

return $this->response->item($user, new UserTransformer)->setStatusCode(200);

自定义响应格式

配置 这章,我们大概的接触了响应格式化。默认的,这个包会自动使用 JSON 格式并设置相关的 Content-Type 头。除了 JSON 格式化,还有一个 JSONP 格式化。这个 formatter 将会用一个回调包裹响应。注册这个格式化你可以简单的替换 JSON formatter 在配置文件或者你的启动文件中。

'formats' => [
    'json' => 'Dingo\Api\Http\Response\Format\Jsonp'
]
Dingo\Api\Http\Response::addFormatter('json', new Dingo\Api\Http\Response\Format\Jsonp);

默认情况下,预计的 query string 中的回调参数是 callback,可以传递第一个参数到 class 的构造函数中去替换。如果 query string 中没有提供回调参数的名字,它将默认的返回 JSON 响应。

如果你需要,你可以注册并使用你自己的 formatters。你的 formatter 需要继承 Dingo\Api\Http\Response\Format\Format。下面的方法需要被定义:formatEloquentModel, formatEloquentCollection, formatArraygetContentType。你可以在预定义格式化类中得到更多的资料,包括提到的抽象类中每个方法需要做什么。

事件

在这个包返回响应之前,首先会 转换 响应。这个过程涉及到运行所有 transformers 以及发送满足配置的格式化响应。如果你需要对响应的变化有更多的控制,你可以使用 ResponseWasMorphedResponseIsMorphing 这两个事件.

app/Listeners 目录中为这两个事件创建监听者。

use Dingo\Api\Event\ResponseWasMorphed;

class AddPaginationLinksToResponse
{
    public function handle(ResponseWasMorphed $event)
    {
        if (isset($event->content['meta']['pagination'])) {
            $links = $event->content['meta']['pagination']['links'];

            $event->response->headers->set(
                'link',
                sprintf('<%s>; rel="next", <%s>; rel="prev"', $links['links']['next'], $links['links']['previous'])
            );
        }
    }
}

如果你想监听事件,可以添加事件和监听者到 EventServiceProvider 中。

protected $listen = [
    'Dingo\Api\Event\ResponseWasMorphed' => [
        'App\Listeners\AddPaginationLinksToResponse'
    ]
];

现在,所有的响应都会包含分页链接,这些链接会放在 Link 头中。

提示,这并不是生产环境的代码,它仅仅只是怎么利用事件的例子。

本文章首发在 Laravel China 社区
上一篇 下一篇
讨论数量: 2
发起讨论


simaguo
Lumen 中 dingo 设置 CustomSerializer
1 个点赞 | 5 个回复 | 分享
li603674060
BaseController 里面都写什么?
0 个点赞 | 3 个回复 | 问答
刻意练习,每日精进。
4
点赞
2700
浏览
2
讨论
译者