我正在使用 Slim 4 框架实现一项服务,该框架几乎总是会返回 JSON 响应。我正在尝试使用类似于以下结构的所有响应保持统一:
{
"status": "success",
"data": {"foo": "bar"} // the actual data relevant to the request
"messages": []
}
在最基本的格式中,这是我做出这样的响应所需的代码:
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface {
// Do something
$response
->getBody()
->write(json_encode([
'status' => 'success',
'data' => [
'foo' => 'bar'
],
'messages' => [],
]));
return $response
->withHeader('Content-Type', 'application/json')
->withStatus(200);
}
现在,我一直在使用一个基本的帮助类,它基本上将大部分样板文件包装成几个静态函数,所以我可以写一个这样的响应:
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface {
// Do something
$data = ['foo' => 'bar'];
return APIResponse::success($response, $data)->into();
}
但是,现在我遇到了一个问题,我想让响应稍微复杂一些,这需要额外的依赖项,例如自定义序列化程序类。天真的选择是继续将额外的依赖项传递给APIResponse::success($response, $serializer, ..., $data)
,但这显然很糟糕,而且不是一个好的长期选择。
我想到的另一个选择是制作一个APIResponseFactory
,它将接受构造函数中的任何依赖项并通过 PHP-DI 填充。那会更干净一些,但是每个路由处理程序都需要注入工厂,而且我仍然需要$response
每次都手动通过。
return $responseFactory->success($response, $data);
所以,我现在正在考虑的是尝试构建一个可以实现的自定义类ResponseInterface
,从而允许我将样板助手自动构建到每个请求处理程序中。我正在查看我的项目中正在使用的当前 PSR7 ResponseInterface 实现,代码注释提到该类永远不应扩展,并建议使用装饰器模式。因此,这是我为当前想法制作的基本伪代码实现。
class MyCustomResponse implements ResponseInterface {
private $serializer;
private $actualResponse;
// any other dependencies
public function __construct(ResponseInterface $actualResponse, Serializer $serializer /*, other dependencies */) {
$this->actualResponse = $actualResponse;
$this->serializer = $serializer;
}
// Use this class as a decorator and pass all ResponseInterface calls to the external implementation
// EDIT: It looks like I can't use `__call` to fulfill the interface, so I'd need to manually define to functions, but you get the gist.
public function __call($name, $args) {
return $this->actualResponse->$name(...$args);
}
public function success($data) {
$this->actualResponse
->getBody()
->write($this->serializer->serialize([
'status' => 'success',
'data' => $data,
'messages' => [],
]));
$this->actualResponse
->withHeader('Content-Type', 'application/json')
->withStatus(200);
return $this;
}
}
因此,我(希望)能够返回这样的响应:
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface {
$data = ['foo' => 'bar'];
return $response->success($data);
}
我的实际问题:这是为 PSR-7 响应处理程序实现自定义帮助方法的正确方法吗?有没有更好的办法?编写这样的辅助函数是不好的做法吗?由于缺乏更好的描述,PSR-7 接口似乎是低级和冗长的,这让我担心编写这样的包装器会以某种方式违背标准的意图。是否有其他方法可以遵循标准但减少样板并保持响应统一?