Zend Expressive 2 — REST API (JSON) — Управление версиями (в шапке) — FastRoute?

Я создаю Zend Expressive 2 REST API (JSON) и хочу напрямую управлять версиями моего API. Я использую Zend ServiceManager + FastRoute для маршрутизации.

Я нашел эти полезные ссылки для управления версиями REST API и решил использовать управление версиями внутри заголовка запроса:

Вопрос:

Как реализовать API-версии; подробно маршрутизация к промежуточному программному обеспечению; в Zend Expressive 2? (используя FastRoute)

Accept Header (JSON API с версией):

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;
}

}

2

Решение

Fastroute создает регулярное выражение в URL и анализирует его. Таким образом, передача атрибута запроса не работает. Я могу придумать несколько способов заставить это работать:

  • Не используйте управление версиями в заголовке, но используйте его в URL. Но так как вы специально просите об этом, я думаю, что это не вариант.
  • Перепишите URL-адрес в ContentTypeJsonApiVersioning и обновите запрос до его передачи маршрутизатору. Так что в основном переписать его /api/v1/resource/id
  • Передайте все запросы API в APiMiddlewareAction и там проверьте версию, переданную в запросе, и загрузите соответствующее действие.

В последнем случае у вас может быть только один маршрут, похожий на:

[
'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

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]