Проблема: Есть большое количество API маршрутов, возвращающих данные в JSON. Эти данные, как правило, представимы в табличном виде. То есть там массив записей. Для части маршрутов создали двойников чтобы вместо JSON выгружался pdf файл. Типа был `/api/reports/yield` добавили `/api/reports/yield/pdf. И не могли не заметить, что получается много копипасты. Поэтому... Хотелка: Добавить что-то в URL как признак "надо в PDF" и автоматически получить этот самый вариант в PDF — для любого GET-запроса к API. В перспективе наверное захочется и другие "рендереры" прикрутить по аналогии с PDF. Да, можно не через URL, а через заголовок запроса типа `Accept` рулить типом, но думаю это не принципиално для задачи. В принципе у меня уже есть решение, даже два, но хочется обсудить, может я не вижу чего-то очевидного. Может уже были обсуждения.
Не видя кода сложно понять откуда именно там "много копипасты" Но если поиграть в ожившую Вангу, то я бы вынес такое решение в миддлварь - это, как видится, наиболее логично в описанной ситуации. Параметры запроса я оставил бы в роутах. В общем, не совсем понятно в чем именно вопрос.
@artoodetoo, может в middleware вынести преобразование в PDF? И от маршрута выбирать класс-преобразователь, ну т.е. "стратегия" получится.
попробуй сделать after middleware, в ней разобрать request/response и подменить ответ по необходимости.
Всем спасибо, укрепили мою уверенность в выбранных методах. Расказываю про свои два решения. Вначале я подумал что "универсальный роут" подойдёт идеально. Вот так это выглядит: Решение 1: маршрут PHP: Route::middleware(['auth:api'])->group(function () { // Route:: // Route:: // Route:: // важно, что это стоит в конце! Route::get('{uri}/pdf', 'DefaultController@getPdfVersion')->where('uri', '^.*'); }); и контроллер. Фишка в том, что я заново формирую объект request уже с моим URI, обращаюсь к ядру и прошу его вернуть response — как это происходит при обычной обработке http запроса. PHP: class DefaultController extends Controller { public function getPdfVersion(string $uri) { /** @var \Illuminate\Http\Request $newRequest */ $newRequest = Request::create("api/{$uri}", 'GET', $_GET, $_COOKIE, $_FILES, $_SERVER, null); /** @var \Illuminate\Http\Response $response */ $response = $GLOBALS['kernel']->handle($newRequest); if ($response->getStatusCode() == 200 && $response->headers->get('Content-Type') === 'application/json') { // ... пропускаю магию, специфичную для конкретного проекта ... // беру json_decode($response->getContent(), true) , прогоняю через шаблон, сохраняю в файл pdf ... return response()->download( storage_path("app/{$fileName}"), $fileName, ['Content-Type' => 'application/pdf'] ) ->deleteFileAfterSend(); } return $response; } } --- Добавлено --- Но потом я решил переписать на middleware. Решение 2. Да, это after-процессинг. Сначала выполняется весь стек мидваров, маршрут и контроллер, затем на обратном проходе я получаю доступ к объекту response и заменяю его. Убрал маршрут и контроллер, теперь признаком является ключ ?render=pdf, что кагбэ подразумевает и другие варианты представления в перспективе. PHP: class ConvertContentMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $response = $next($request); if ($request->has('render')) { switch ($request->render) { case 'pdf': // ... пропускаю магию, специфичную для конкретного проекта ... // беру json_decode($response->getContent(), true) , прогоняю через шаблон, сохраняю в файл pdf ... break; default: throw new \Exception('Unknown renderer ' . $request->render); } return response()->download( storage_path("app/{$fileName}"), $fileName, ['Content-Type' => 'application/pdf'] ) ->deleteFileAfterSend(); } return $response; } }