首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ZendExpression2-RESTAPI (JSON) -版本控制(在标头中)- FastRoute?

ZendExpression2-RESTAPI (JSON) -版本控制(在标头中)- FastRoute?
EN

Stack Overflow用户
提问于 2017-10-21 08:38:36
回答 1查看 773关注 0票数 2

我正在构建一个ZendExpression2RESTAPI (JSON),并希望直接对我的API进行版本化。我使用Zend ServiceManager + FastRoute进行路由。

我找到了REST版本控制的有用链接,并决定在请求头中使用版本控制:

问题:

如何实现api版本控制;详细的路由到中间件操作;在ZendExpression2中?(使用FastRoute)

接受标题(带有版本的JSON):

代码语言:javascript
复制
Accept: application/vnd.api+json;version=2

所需结构(应用):

代码语言:javascript
复制
/
 config/
 data/
 public/
 src/
     App/
         V1/
            Action/
                   SomeResource.php        // <- in Version 1
                   ...
         V2/
             Action/
                   SomeResource.php        // <- in Version 2
                   ...
         ...
vendor/
...

我的代码片段:(版本检测工作,但如何路由?)

pipeline.php

代码语言:javascript
复制
<?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

代码语言:javascript
复制
<?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

代码语言:javascript
复制
<?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;
    }

}
EN

回答 1

Stack Overflow用户

发布于 2017-10-22 05:53:11

fastroute所做的就是在URL上抛出一个regex并解析它。因此,传递请求属性不起作用。我可以想出几种方法让它发挥作用:

  • 不要在标题中使用版本控制,而是在url中使用它。但既然你是专门要求的,我想这不是一个选择。
  • 在ContentTypeJsonApiVersioning中重写URL并在请求传递给路由器之前更新它。所以基本上把它重写到/api/v1/resource/id
  • 将所有api请求传递给APiMiddlewareAction,在那里检查在请求中传递的版本,并加载正确的操作。

在最后一种情况下,您可能只有一条类似于以下内容的路径:

代码语言:javascript
复制
[
    'name'            => 'api',
    'path'            => '/api/{resource:\w+}[/{resourceId:\d+}[/{relation:\w+}[/{relationId:\d+}]]]',
    'middleware'      => ApiMiddleware::class,
    'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
    'options'         => [
        'defaults' => [
        ],
    ],
],

可能还有更多的解决方案。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46861533

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档