Упростить шаблон API в контроллерах Laravel?

#laravel #api #rest #model-view-controller

#laravel #API #остальное #модель-представление-контроллер

Вопрос:

Когда я пишу API с помощью Laravel, я часто использую тот же метод, что и GitHub API v3. Я добавляю URL-адреса для облегчения навигации во время разработки, а также для пользователей, которые будут разрабатывать с использованием этого API.

В этом примере я вручную добавляю URL-адреса в каждое поле, а затем добавляю a count для пейджеров во внешнем интерфейсе. Иногда у меня возникают более сложные вещи, если я хочу добавить необходимое для фильтрации результатов (если используется с Vuetify или Kendo Grid).

 class UserController extends Controller
{
    function index() {
        $users = User::all()->each(function ($item, $key) {
            $item['activities'] = url("/api/users/{$item['id']}/activities");
            $item['classrooms'] = url("/api/users/{$item['id']}/classrooms");
        });
        return [
            'count' => count($users),
            'courses' => $users,
        ];
    }
}
  

Есть ли способ сделать этот код менее шаблонным? Есть ли пакет, который делает все из коробки?

Ответ №1:

Я fractal большой поклонник fractal пакета spaties. Это позволяет преобразовывать объекты в ответы.

Во фрактальных сериализаторах и трансформаторах есть две концепции. Сериализаторы — это весь запрос, метаданные и т. Д. Трансформатор — это способ преобразования каждой модели или объекта. Обычно вы не стали бы создавать пользовательские сериализаторы, но в вашем случае это может решить большую часть ваших проблем.

 use LeagueFractalSerializerArraySerializer;

class YourSerializer extends ArraySerializer {
    public function collection($resourceKey, array $data)
    {
        return [
            $resourceKey => $data,
            'count' => count($data),
        ];
    }
}
  

Создайте свой трансформатор для вашего пользователя. Другая важная вещь, которую вы получаете за это, — это то, что у вас есть одна игра, которая отвечает за преобразование. Вместо того, чтобы у каждого контроллера должна быть своя логика, которая будет распространена, и вы должны не забыть ее включить.

 use LeagueFractalTransformerAbstract;

class AccountBalanceTransformer extends TransformerAbstract
{
    public function transform(User $user)
    {
        return [
            'id' => $user->id,
            'name' => $user->id,
            // other user fields
            'activities' => url("/api/users/{$user->id}/activities"),
            'classrooms' => url("/api/users/{$user->id}/classrooms"),
        ];
    }
}
  

Вы должны назначить serializer в своей fractal.php конфигурации.

 'default_serializer' => YourSerializer::class,
  

Теперь вы должны иметь возможность преобразовывать свои ответы следующим образом.

 return fractal($users, new UserTransformer())
    ->withResourceName('courses')
    ->respond(Response::HTTP_OK);
  

Чтобы упростить его использование и избежать повторения, я обычно использую метод на родительском контроллере, подобный этому. При настройке трансформатора на объекте.

 public function respond($data, $resourceKey, $status = Response::HTTP_OK) {
    return fractal($data, $this->transformer)
        ->withResourceName($resourceKey)
        ->respond($status);
}
  

Это приведет к ответу, аналогичному тому, который был указан в вопросе.

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

1. Вероятно, есть также решение с использованием eloquent resources, я был большим поклонником fractal до появления eloquent resources и все еще думаю, что он немного лучше подходит для моих нужд.

2. Выглядит потрясающе! Как где вы сохраняете свои трансформаторы (в AppTransformer )? Есть ли способ избежать use AppTransformerMyTransformer в каждом контроллере?. Я думаю return factal($users, new MyTransformer) , это некрасиво. Может быть, есть способ написать это: return $users->transform() ?

3. Я сохраняю их в App Transformers. Как вы их преобразуете, зависит от вас, я вставляю каждый трансформатор в конструктор контроллера, который работает лучше всего для меня. Поскольку это имеет смысл, поскольку ответственность контроллеров заключается в делегировании преобразования ответов.

4. … так что да, сейчас я использую Фрактал.