Реализовать управление версиями RESTful API с помощью PHP / Slim и Apache

#php #apache #rest #.htaccess #slim

#php #apache #rest #.htaccess #тонкий

Вопрос:

После некоторых комментариев я создаю вопрос о CodeReview.


Я хочу создать RESTful API с помощью Apache / PHP и Slim Framework (3.x). API должен поддерживать управление версиями на основе URI, такое как <host>/rest/api/v1/<resource> и <host>/rest/api/latest/<resource> .

В целом я нашел решение, которое работает, но я не очень доволен своим решением, и я хочу знать, что я могу сделать лучше. Я новичок в Slim. Я ищу новые идеи и то, как я могу улучшить свои знания о Slim.

  • Общие улучшения или комментарии?
  • У вас есть лучшее / более простое решение?
  • Видите ли вы проблемы в моем решении?
  • Улучшения для правил .htaccess / перезаписи
  • Ссылки на реальные реализации RESTful API с помощью Slim
  • ….

Я с нетерпением жду ваших ответов, и мне будет любопытно узнать, что нового.


Каждая новая версия должна быть новым проектом, имеющим собственную независимую кодовую базу. Отправка версий должна выполняться сервером Apache, а не в коде PHP / Slim. Я нашел некоторый пример, который реализует различные версии API в проекте on с использованием метода group. Но я не очень доволен этим решением. Я чувствую себя лучше, когда у меня есть независимые проекты для независимых версий.

Я создаю структуру папок / файлов в папке htdocs следующим образом:

 rest
  --api
      -v1
         -.htaccess
         -api.php
      -v2
         -.htaccess
         -api.php
      -.htaccess
  

Реализация API находится в файле api.php . Сопоставьте вызовы, подобные /rest/api/v1/books моей реализации, я создаю в каждой папке версии .htaccess файл, который содержит правила для перезаписи модуля Apache:

 RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^$ / [QSA,L]
RewriteRule ^.*$ api.php [QSA,L]
  

Первое правило перезаписи необходимо для соответствия вызову /rest/api/v1 , а второе правило переписывает пути, подобные /rest/api/v1/books реализации.

В api.php я создаю несколько маршрутов

 $app->get('/books', function ...
$app->get('/books/{id}', function ...
  

Все работает нормально, если я использую явную версию в URI ( <host>/rest/api/v2/books ). Для удобства, если я создам псевдоним latest ( /rest/api/latest/books ), который перенаправляет вызов псевдонима на последнюю версию версии API.

Поэтому я создаю файл rest/api/.htaccess , который переписывает URI в реализацию:

 RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^latest.*$ ./v2/api.php [QSA,L]
  

Правило перезаписи работает нормально, и вызывается реализация v2. Но маршруты больше не совпадают. Я обнаружил, что исходный путь теперь является частью path.

 /rest/api/v2/books -> /books
/rest/api/latest/books -> /rest/api/latest/books
  

Если бы я изменил правила подобным образом, это сработало бы, но мне не нравится реализовывать каждое правило дважды.

 $app->get('/rest/api/latest/books', function ...
$app->get('/rest/api/latest/books/{id}', function ...
  

Поэтому я написал функцию промежуточного программного обеспечения, которая выполняет обрезку /rest/api/latest пути до сопоставления маршрутов.

 $app->add(function (Request $request, Response $response, callable $next) {
    $uri = $request->getUri();
    $path = $uri->getPath();
    if (substr($path,0,16) == "/rest/api/latest") {
        $uri = $uri->withPath(substr($path,16));
        return $next($request->withUri($uri), $response);
    }
    return $next($request, $response);
});
  

Теперь я могу использовать одни и те же правила для обоих случаев, явного вызова версии и неявного вызова версии.

Комментарии:

1. Вы должны задать все эти вопросы на CodeReview

2. Как говорится в предыдущем комментарии, ваш вопрос кажется слишком широким и не по теме для SO. Но раз уж мы здесь, мне любопытно, почему вам удобнее иметь независимые проекты вместо группировки маршрутов? Я имею в виду, можете ли вы объяснить свое решение в деталях? Вы пробовали группировать маршруты? Кажется, вы создаете себе слишком много проблем, просто чтобы уйти от метода сгруппированных маршрутов, который на самом деле является довольно удобным решением вашей проблемы.

3. Спасибо за подсказку. Я создаю вопрос по CodeReview