Создание собственного API-интерфейса {JSON: API} средствами Laravel
С тех пор, как я начал работать с API в Laravel, я использовал потрясающий пакет Fractal
от The League of Extraordinary Packages.
И он отлично себя зарекомендовал для преобразования исходных моделей в JSON: API и другие методы сериализации, и до сих пор это был единственный вариант.
Введение в классы Resource Laravel 5.5
Начиная с Laravel 5.5, теперь у нас есть классы Resource, которые мы можем использовать для наших API-интерфейсов из коробки без необходимости установки каких-либо сторонних пакетов.
Что такое классы Resource и почему я должен его использовать?
Класс Resource — это способ преобразования данных из одного формата в другой. Проще говоря, если у нас есть модель Article(Статьи), и мы хотим манипулировать данными или удалять определенные поля из модели, прежде чем отправлять наш ответ(response) сервера, это трудно сделать, просто ответив:
Конечно, это даст вам положительный результат, может что-то вроде этого:
Но что, если вы хотите форматировать свои ответы по стандарту, такой как JSON: API или любой из других многочисленных стандартов. Нам нужно переопределить реализацию модели toArray
но теперь мы нарушаем правило единой ответственности. Почему модель должна заботиться о том, как форматировать ответ конечному пользователю? Так нельзя! и теперь мы можем использовать класс Resource начиная с Laravel 5.5. Вместо того, чтобы делать то, что мы делали выше, мы теперь можем создать Resource Laravel, используя artisan
и преобразовывая нашу модель любым способом.
В следующей части этой статьи я расскажу вам, как использовать новые классы Resource Laravel для реализации примера из спецификации JSON: API , которая выглядит примерно так:
Создадим наше приложение Laravel
Сначала нужно создать тестовое приложение для работы:
laravel new articles-api
Простите меня, поскольку я постараюсь пропустить скучные детали установки. Я также собираюсь предположить, что вы знаете, как подключиться к базе данных и настроить среду и т. Д., Чтобы мне не пришлось описывать это в этой статье.
Продолжение …
Создайте нашу базу данных и модели
php artisan make:model People -mf
php artisan make:model Comment -mf
php artisan make:model Article -crmf
Поскольку это учебное пособие, мы не хотим тратить время на скучные вещи, поэтому эта команда создает model, resource controller ( cr
), migration ( m
) и factory ( f
) за один раз. Вууух!
Давайте заполним их некоторыми данными, чтобы мы могли начать работать с материалом.
Откройте файлы миграции и добавьте:
Теперь, когда у вас есть миграции, вы можете выполнить миграцию:
php artisan migrate
Вы также получаете factory классы, доступные для загрузки некоторых тестовых данных, но я оставлю это до вас, попробуйте сами заполнить пробелы.
Построение нашего JSON: API с использованием класса Resource
Теперь, когда у нас есть наша база данных и, по-видимому, вы заполнили свои таблицы некоторыми тестовыми данными, мы можем перейти к материалу и к чему вы действительно пришли сюда.
Немного теории
Как преобразовывать данные в ответ для клиента, когда вы работаете с resources? У нас в основном есть 2 типа, элемент и коллекция. Элемент resource, как вы могли догадаться, в основном представляет собой одно-единственное представление нашей модели, где в качестве коллекции представлено множество элементов. Коллекции могут также содержать метаданные и другую навигационную информацию.
В терминах JSON: API элемент мы можем представлять так;
А коллекции будут представлены таким образом (в его основной форме);
Теперь, когда мы знаем разницу между элементом и коллекцией, попытаемся смоделировать их с помощью классов Resource .
Сначала нам нужно сгенерировать 2 класса. Один для обработки элемента, а другой — для обработки коллекции . С помощью artisan
выполним следующее.
php artisan make:resource ArticleResource
php artisan make:resource ArticlesResource --collection
У вас должна появиться новая директория app/Http/Resources
в которой будут находиться все эти ресурсы.
В каждом из этих классов у вас будет метод toArray
, в котором мы преобразуем наши модели так, как мы хотим их. Так что давайте изменим App\Http\Resource\ArticleResource
так, чтобы он преобразовал нашу модель статьи в ресурс JSON: API:
Как вы можете видеть, у нас есть для начала верхний уровень type
, id
и ключи attributes
. Это мы конечно будем расширять, включая links
и relationships
, но сначала давайте создадим контроллер и роуты. Так образом мы сможем увидеть нашу выполненную, на данный момент, работу.
php artisan make:controller --resource ArticleController
Эта команда даст нам контроллер, основанный на ресурсах, для совместного использования нашего RESTful API. Теперь нам нужно сообщить нашим экшинам(действиям) контроллера, чтобы использовать наш вновь созданный ресурс в методе show, поэтому добавим его.
И добавим в роут routes/api.php
;
Здесь для простоты мы можем просто использовать роут на основе ресурсов, мы добавим к нему немного, чтобы он не был потрачен впустую.
Итак, теперь у вас должен быть полностью функциональный API, который может показать ресурс статьи, перейдя к /api/articles/{id}
, вы должны получить ответ наподобие этого:
Очевидно, вам нужно добавить некоторые данные в свою базу данных и обработать API
СОВЕТ: выполните команду
php artisan serve
и перейдите по http://127.0.0.1/api/articles/1 в Postman или браузере наблюдая за магией.
Обеспечение соответствия JSON: API
Все это замечательно, и из коробки работает хорошо, но эта статья посвящена использованию классов Resource для генерации JSON: API. Для этого элемент не должен иметь ключ верхнего уровня data
. Что же, хорошо, Laravel позволит нам сделать это легко, нам просто нужно сообщить ресурсу, мы не хотим что бы он был завернут, поэтому перед вызовом ресурса нам нужно вызвать статический метод withoutWrapping()
, просто вот так:
Теперь, когда вы вызовете по http://127.0.0.1/api/articles/1 вы получите что то на подобие
Здорово, это было легко. Итак, теперь давайте добавим еще кое-что из JSON: API, такое добро как links
и relationsships
. Откройте ArticleResource
и добавьте следующее.
Вот так просто мы добавили наши relationships(связи) и links(ссылки) на статьи. Ссылка self
будет работать из коробки, потому что мы добавили роут ресурса до контроллера, что бы он знал, какой этот роут, но у нас также есть новый ресурс для наших связей, которые необходимо будет создать. Легко нам поможет в этом artisan
:
php artisan make:resource ArticleRelationshipResource
И просто для целесообразности мы также создадим остальную часть наших ресурсов, они нам понадобятся позже.
php artisan make:resource AuthorIdentifierResource
php artisan make:resource CommentIdentifierResource
php artisan make:resource ArticleCommentsRelationshipResource --collection
Давайте теперь мы перейдем $this
в наш ArticleRelationshipResource
чтобы у нас был доступ к модели Article
и ее связям.
Обратите внимание, что в этом классе мы имеем новый метод, with
который используется для добавления метаданных в наши ресурсы. Это удобно, чтобы разделить все данные, не основанные на сущности, из вашего ресурса.
Таким образом, мы теперь обрабатываем ссылки и отношения, и мы в значительной степени выполняем создание ресурса элемента. Я дам вам возможность проработать над другими ресурсами и данными, которые нужны (подсказка: ответ находится на github-link в конце статьи).
Коллекция Resources
Последнее, что нужно сделать, это ресурс коллекции, ну это не может быть ничего проще. Давайте откроем ArticleController
и сделаем это.
Так же, метод show
, просто возвращает ресурс и передает ему коллекцию статей в его конструкторе. В этом случае мы хотим получить разбитый список Articles
и загружать нужные нам связи. Наш ArticlesResource
выглядит так.
Насколько это все легко, мы просто используем ArticleResource
. мы уже сделали всю тяжелую работу с помощью использованием статического метода collection
, передающего коллекцию разбитых пагинацией статей контроллера, который должен быть преобразован.
Включенные объекты
Это все очень хорошо, но нам по-прежнему не хватает одной части нашего ресурса JSON: API, и это уникальный список included
сущностей. Итак, давайте добавим их сейчас;
Теперь вы можете увидеть причину, по которой мы загрузили связи в контроллере. JSON: API должен быть минимален на выходе, нам нужен уникальный список всех связанных ресурсов, которые могут ссылаться на идентификаторы ресурсов, наподобие "data": {"type": "people", "id": "9"}
.
Оказывается, это довольно прямо связано с методами Collection flatMap
и колбэком map
. flatMap
необходим для связей коллекции и map
необходим для установления связи с элементами. Они вернут коллекции наших связей для всех объектов нашей коллекции, поэтому в этом случае мы имеем несколько статей(articles) с авторами(authors) и комментариями(comments). Мы получаем новые коллекции всех авторов и комментарии для всех статей, а затем объединяем их и делаем их уникальными.
После того, как у нас есть уникальный список всех связей, нам нужно получить соответствующий класс ресурсов и создать экземпляр с нашим включением. Мы просто возвращаем эту новую коллекцию ресурсов и присваиваем ее ключу included
, и мы вроде закончили. Вы должны ожидать, что ваш api выведет что-то наподобие;
Итак, теперь вы можете увидеть список уникальных included
ресурсов, которые относятся ко всем нашим статьям.
Вывод
Я попытался показать, как использовать ресурсы начиная с Laravel 5.5 для создания ответов, совместимых с JSON: API, и это удивительно легко, если вы поймете основы работы.
Если вы следуете по коду, я не стал включать весь код в эту статью, так как это сделало бы статью очень повторяющейся и скучной (надеюсь, это уже не скучно). Если вы хотите изучить эти Resources больше, вы можете checkout
мое репо на github.com, который является полностью работающим приложением, и, пожалуйста, если вы видите какие-либо ошибки или можете найти лучший способ обработки included
данных, отправьте PR, и я рассмотрю его или в по крайней мере буду обсуждать с вами.
Надеюсь, вы нашли эту статью информативной и начали использовать ресурсы Laravel.