Как разработчик REST API, мне нужно протестировать мое приложение.Недавно я перешел к спецификации OpenAPI, и я действительно хочу проверить свои ответы API на это.Мое приложение основано на Lumen.
Хотя маршруты без параметров пути не вызывают проблем, я сталкиваюсь с проблемой «обратной маршрутизации».Например, в моих функциональных тестах я тестирую маршрут: GET / themes / {themeId} / questions, который должен возвращать questions
, связанный с theme
числом themeId
.
.фактический URI может быть что-то вроде /themes/17/questions
.Проблема в том, что мне нужно найти точный шаблон с {params}, чтобы проверить мой API на соответствие спецификации.Чтобы было ясно, мне нужен способ:
/themes/17/questions => /themes/{themeId}/questions
Я уже нашел какое-то решение, но я абсолютно не удовлетворен, и это кажется очень грязным:
/**
* Get the OpenAPI URI based on the actual request URI.
*
* @param string $method The HTTP method (GET, POST, PUT, PATCH, DELETE etc.)
* @param string $actualUri The actual request URI
*
* @return string
*/
public function getOpenAPIUri(string $method, $actualUri)
{
$currentRouter = $this->dispatch($method, $actualUri); // Calls the Lumen dispatcher
$filteredRoutes = Collection::make($this->app->router->getRoutes())
// Reject routes which do not match the method
->reject(function ($routeData, $routeKey) use ($method) {
return !Str::startsWith($routeKey, strtoupper($method));
})
// Reject routes which do not match the controller/action
->reject(function ($routeData) use ($currentRouter) {
if (!isset($routeData["action"]["uses"])) {
return true;
}
return $currentRouter[1]["uses"] !== $routeData["action"]["uses"];
})
// Reject routes which have not the same amount of parts (splitted by "/")
->reject(function ($routeData) use ($actualUri) {
$actualParts = explode("/", trim($actualUri, "/"));
$routeParts = explode("/", trim($routeData["uri"], "/"));
return count($actualParts) !== count($routeParts);
})
// Reject routes which does not have the same arguments
->reject(function ($routeData, $routeKey) use ($currentRouter) {
$pattern = "/{([a-zA-Z]+):[a-zA-Z0-9\/\\\+\-_\[\]\*\{\}\|\.\^]+}/";
$strippedUri = preg_replace($pattern, '{$1}', $routeKey);
$paramKeys = Collection::make(array_keys($currentRouter[2]))->map(function ($param) {
return "{{$param}}";
});
return !Str::contains($strippedUri, $paramKeys->toArray());
});
if ($filteredRoutes->isEmpty()) {
return $actualUri;
} else {
$match = $filteredRoutes->first();
return $match["uri"];
}
}
Любое предложение будет с благодарностью!