2017-10-21 5 views
2

Zend Expressive 2 REST API (JSON)를 만들고 API를 직접 버전 관리하려고합니다. 라우팅을 위해 Zend ServiceManager + FastRoute를 사용합니다. Zend Expressive 2 - REST API (JSON) - 버전 관리 (헤더) - FastRoute?

나는 REST API의 버전이 유용한 링크를 발견하고 요청 헤더 내부 버전을 사용하기로 결정 :

질문 :

어떻게 구현 API 버전 관리; 상세히 미들웨어 동작에 대한 라우팅; 표현형 표현 2에서? (FastRoute 사용)

헤더 (버전 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; 
    } 

} 

답변

0

은 무엇 fastroute 수행하는 URL에서 정규식을 던져 구문 분석이다. 따라서 요청 속성 전달은 작동하지 않습니다. 나는 그것을 작동하게하는 몇 가지 방법을 생각할 수 있습니다 :

  • 헤더에서 버전 관리를 사용하지 말고 URL에서 사용하십시오. 그러나 당신이 그것을 요구하고 있기 때문에 나는 그것이 선택이 아니라고 생각합니다.
  • ContentTypeJsonApiVersioning에서 URL을 다시 작성하고 요청이 라우터로 전달되기 전에 업데이트하십시오. 그래서 기본적으로 다시 작성하십시오 /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' => [ 
         ], 
        ], 
    ], 
    

    아마 더 솔루션이 있습니다

이 지난 경우 다음과 유사한 하나의 경로를 가질 수있다.