#php #laravel #api
#php #laravel #API
Вопрос:
У меня есть простой веб-сайт, на котором работает Laravel Jetstream с включенными командами. На этом веб-сайте вы можете создавать различные «задачи для выполнения», которые принадлежат команде. У меня есть модель называется Task
.
Я пытаюсь создать общедоступный API, чтобы мои пользователи могли запрашивать свои задачи из своих собственных приложений. В моем routes/api.php
файле я добавил это:
Route::middleware('auth:sanctum')->group(function(){
Route::apiResources([
'tasks' => AppHttpControllersAPITaskController::class,
]);
});
И затем в TaskController
, я только начал кодировать index
метод:
/**
* Display a listing of the resource.
* @queryParam team int The team to pull tasks for.
* @return IlluminateHttpResponse
*/
public function index()
{
if(request()->team){
$tasks = Task::where('team_id', request()->team)->get();
return TaskResource::collection($tasks);
}
return response([
'status' => 'error',
'description' => "Missing required parameter `team`."
], 422);
}
Теперь это работает нормально. Я могу сделать запрос GET https://example.org/api/tasks?team=1
и успешно выполнить все связанные с ним задачи team.id = 1
.
Однако, что, если я хочу включить несколько параметров запроса — некоторые обязательные, другие только необязательные. Например, если я хочу разрешить пользователям доступ ко всем задачам с заданным статусом:
https://example.org/api/tasks?team=1amp;status=0
Каковы наилучшие методы для этого? Поскольку я вижу, к чему все идет сейчас, я закончу с большим количеством if/else
инструкций, просто чтобы проверить допустимые параметры и дать правильный код ответа на ошибку, если чего-то не хватает.
Редактировать
Я изменил свой URL на: https://example.org/api/teams/{team}/tasks
— так что теперь team
он должен быть добавлен к URL. Однако я не уверен, как добавлять фильтры с помощью конструктора запросов Spatie:
public function index(Team $team)
{
$tasks = QueryBuilder::for($team)
->with('tasks')
->allowedFilters('tasks.status')
->toSql();
dd($tasks);
}
Итак, приведенное выше просто выводит:
"select * from `teams`"
Как я могу выбрать связь tasks
с team
помощью фильтров?
Ответ №1:
Правильный путь
В качестве продвинутого решения я создал несколько пользовательских способов обработки параметров поискового запроса. Что вы в основном и хотите сделать, лучшим решением на сегодняшний день является конструктор запросов пакетов spatie.
QueryBuilder::for(Task::class)
->allowedFilters(['status', 'team_id'])
->get();
Эта операция будет выполнять то же самое, что вы хотите сделать, и вы можете фильтровать ее следующим образом.
?fields[status]=1
По моему опыту, делать team_id доступным для поиска по команде и подобным случаям не стоит, просто используйте его один к одному между столбцами и вводом. Пакет обладает широкими возможностями для особых случаев и настройки.
Простой способ
Что-то столь же прямое, как ваша проблема, не требует, чтобы пакет отклонялся от курса. Это просто удобно и позволяет избежать написания некоторого кода котельной.
Это довольно простая задача, когда у вас есть параметр запроса и столбец, в котором вам нужно выполнить поиск. Это может быть представлено в виде массива, где параметр $key
запроса и $value
столбец.
$searchable = [
'team' => 'team_id',
'status' => 'status',
];
Вместо того, чтобы выполнять кучу операторов if, вы можете упростить это. Проверка, соответствует ли запрос вашему $searchables
, и если действовать по нему.
$request = resolve(Request::class);
$query = Task::query();
foreach ($this->seachables as $key => $value) {
if ($query->query->has($key)) {
$query->where($value, $query->query->get($key))
}
}
$tasks = $query->get();
Это довольно простой пример, и здесь возникает проблема, не связанная с пакетом. Вы должны подумать о том, как обрабатывать запросы типа handle, запросы отношений и т. Д.
По моему опыту, расширение $value
до массива или включение замыканий для изменения способа работы логики в построителе запросов может быть вариантом. Это короткое появление простого решения.
Подведение итогов
Здесь у вас есть два решения, где на самом деле оба верны, найдите то, что соответствует вашим потребностям, и посмотрите, что вы можете использовать. Это довольно сложная проблема для прагматического решения, поскольку простой способ часто ухудшается, поскольку необходимо реализовать более явную функциональность поиска. С другой стороны, использование пакета может быть излишним, создавать странные зависимости, а также принуждать вас к определенному подходу к дизайну. Выберите свой яд и надейтесь, что хотя бы это даст некоторые рекомендации, которые могут привести вас в правильном направлении.
Комментарии:
1. Какой подробный и очень хорошо сформулированный ответ. Отличные объяснения, недостатки различных решений и хорошо написанные примеры. Это именно то, что я искал! Спасибо!
2. Я внес небольшую правку в свой OP, так как я немного изменил URL API. Не возражаете, если я быстро взгляну?
3. Как вы отправили параметр запроса для своего примера? он не будет искать, если
4. Дох! Это действительно было причиной. Я сделал это так:
?status=1
. Изменен на?filter[status]=1
и все работает. Спасибо!