我正在构建一个ZendExpression2RESTAPI (JSON),并希望直接对我的API进行版本化。我使用Zend ServiceManager + FastRoute进行路由。
我找到了REST版本控制的有用链接,并决定在请求头中使用版本控制:
问题:
如何实现api版本控制;详细的路由到中间件操作;在ZendExpression2中?(使用FastRoute)
接受标题(带有版本的JSON):
Accept: application/vnd.api+json;version=2所需结构(应用):
/
config/
data/
public/
src/
App/
V1/
Action/
SomeResource.php // <- in Version 1
...
V2/
Action/
SomeResource.php // <- in Version 2
...
...
vendor/
...我的代码片段:(版本检测工作,但如何路由?)
pipeline.php
<?php
// ...
// The error handler should be the first (most outer) middleware to catch
// all Exceptions.
$app->pipe(ErrorHandler::class);
$app->pipe(ContentTypeJsonApiVersioning::class); // <-- detect version work quite well
$app->pipe(ServerUrlMiddleware::class);routes.php
<?php
// ...
//
$app->route('/api/some-resource[/{id:\d+}]',
[
Auth\Action\AuthAction::class,
Zend\Expressive\Helper\BodyParams\BodyParamsMiddleware::class,
App\Action\SomeResourceAction::class
],
['GET', 'POST', 'PUT', 'DELETE'],
'api.route.name'
);ContentTypeJsonApiVersioning.php
<?php
namespace App\Middleware;
use Fig\Http\Message\StatusCodeInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Middleware to detect accept is JSON API (application/vnd.api+json) and separate version
*/
class ContentTypeJsonApiVersioning
{
/**
* @const string
*/
const EXPECTED_TYPE_JSON_API = 'application/vnd.api+json';
/**
* Execute the middleware.
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param callable $next
*
* @throws \InvalidArgumentException
*
* @return ResponseInterface
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
// error: return response with code: 415
$return = $response->withStatus(StatusCodeInterface::STATUS_UNSUPPORTED_MEDIA_TYPE);
$acceptHeader = $request->getHeader('Accept');
if (isset($acceptHeader[0])) {
$data = $this->_processAcceptHeader($acceptHeader[0]);
if (self::EXPECTED_TYPE_JSON_API === $data['accept']) {
// continue processing
$return = $next($request->withAttribute('version', $data['version']), $response);
}
}
return $return;
}
/**
* @param string $acceptHeader
* @return array
*/
protected function _processAcceptHeader(string $acceptHeader) : array
{
// expected: "application/vnd.api+json; version=2.1"
$data = \explode(';', $acceptHeader);
$return = [
'accept' => $data[0],
'version' => '1'
];
// on 2 items, 2nd is version parameter
if (2 === \count($data)) {
// split: "version=2.1" to "2.1"
list(,$return['version']) = \explode('=', \trim($data[1]));
}
return $return;
}
}发布于 2017-10-22 05:53:11
fastroute所做的就是在URL上抛出一个regex并解析它。因此,传递请求属性不起作用。我可以想出几种方法让它发挥作用:
/api/v1/resource/id在最后一种情况下,您可能只有一条类似于以下内容的路径:
[
'name' => 'api',
'path' => '/api/{resource:\w+}[/{resourceId:\d+}[/{relation:\w+}[/{relationId:\d+}]]]',
'middleware' => ApiMiddleware::class,
'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
'options' => [
'defaults' => [
],
],
],可能还有更多的解决方案。
https://stackoverflow.com/questions/46861533
复制相似问题