Если мы говорим о shared-nothing architecture, используемой в PHP, кодогенерация — хороший способ сократить время бутстрапа приложения. Те же Doctrine и Symfony DI работают по такому принципу.
Понятное дело, что мы можем отказаться от конфигов в каком-то промежуточном формате и сразу писать код, но это менее удобно.
Да мы, в общем, ничего не изобретали :) JSON API — отдельная спека. Если сравнивать её с GraphQL, она несколько менее гибкая, но более простая в использовании.
Для того, чтобы эффективно использовать GraphQL, неплохо бы уметь параллельно опрашивать источники данных. В PHP есть разные способы для этого, но все они, так или иначе, имеют проблемы. Поэтому наш выбор пал на JSON API — её гибкости достаточно для наших клиентов, а реализация на бэке не требует костылей.
Безусловно, но всё слишком сильно зависит от конкретного случая.
Время на «сделать запрос» можно разделить на две составляющие: это время, которое будет потрачено на установление соединение, и время, которое нужно серверному приложению для бутстрапа. Первой составляющей, в общем-то, отчасти можно принебречь, поскольку HTTP/2 поддерживает мультиплексацию, упаковывая несколько запросов в одно соединение.
Так вот, если время, которое приложение потратит на генерацию ответа клиенту, сравнимо с временем, потраченным на сетевое взаимодействие и бутстрап (скажем, API достаёт уже подготовленный ответ из кеша), правда на вашей стороне.
Однако, если получение запрошенных коллекций требует выполнения какой-то сложной бизнес-логики, ситуация перестаёт быть такой однозначной, и тут вполне может выиграть распараллеливание запросов.
Мы преобразовываем json в модели и обратно: таким образом, в коде эндпойнта мы вообще никак не взаимодействуем с сущностями (под сущностями я понимаю те объекты, которые видит клиент нашего API). Кажется, что в данном случае единственное изменение требований, которое сделает такое пребразование неудобным — это отказ JSON API.
Разумеется, есть сложные случаи, когда одна модель должна распасться на несколько сущностей, или, напротив, одна сущность состоит из нескольких моделей — но такие кейсы мы умеем обрабатывать.
Не могли бы вы рассказать в общих чертах, как вы выполняете обратную трансформацию?
Ну и про отказ от бэкенда я вас, честно говоря, не понял :)
либо тупой CRUD, но тогда в GraphQL-ный шлюз со временем неминуемо утечёт часть бизнес-логики, что нежелательно,
либо то, что описывает уважаемый VolCh, и тут, как мне кажется, перспектива получить "единый API на REST" разобьётся о скалы суровой реальности: разным GraphQL-серверам будет хотеться разных данных и PHP-шный бекенд будет вынужден удовлетворять запросы всех.
Я не работал с fractal, однако, навскидку, этот проект не выглядит хорошим кандидатом для расширения под наши хотелки:
fractal, как и многие другие решения, предлагает писать билдеры сущностей (в fractal они именуются трансформерами) — мы же, напротив, хотели уйти от кучи бесполезных классов, внутри которых делается что-нибудь типа
return ['id' => (int) $item->id];
судя по устройству этих самых трансформеров, fractal умеет превращать модели в некие сущности, но не наборот: если клиент прислал нам некую сущность для сохранения, нам придётся руками преобразовывать её в модель (искать в базе, обновлять поля и т. д.)
fractal из-за своей архитектуры не умеет и, видимо, не научится делать eager-loading для связей: для lazy-loading они целый синтаксис сделали (довольно приятный, к слову), для eager — делай всё сам.
Если клиент хочет получить несколько коллекций сущностей за один вопрос, а мы у себя в коде будем собирать эти коллекции последовательно, в чем профит? Клиенту проще параллельно отправить несколько запросов.
Получается, что запрос клиента обрабатывается GraphQL-сервером на Node, который отправляет запросы к PHP-бекенду, объединяет ответы и отдаёт результат клиенту обратно. В таком подходе лично мне не нравится наличие промежуточного слоя (Node), и, кроме того, есть ощущение, что со временем бизнес-логика начнёт размазываться по JS и PHP.
1. Ну, спека-то, всё же, не наша. Смею предположить, что в момент перехода на JSON API вменяемой имплементации GraphQL на PHP не было. Однако, даже если я не прав, в GraphQL смущает другое: параллельное получение данных из разных источников на PHP хоть и возможно, но не без костылей.
2. Вариант с билдером показался более универсальным.
3. Swagger-UI.
Насчёт клиентов вы правы, но как быть с сервером? Нам, как бекенду, важно не только договориться с клиентом о том, как будут выглядеть сущности в API, но и уметь генерировать эти сущности из моделей. Насколько я понимаю, для сервера swagger-gen может просто нагенерить пустых экшенов.
На данный момент для велосипеда актуализируется документация и специфичный для нашего проекта код выносится из кода велосипеда в код основного проекта. Следите за новостями в нашем блоге :)
Переход на новую версию, о которой шла речь в статье, произойдёт, но называть какие-то ETA я бы не хотел :)
Понятное дело, что мы можем отказаться от конфигов в каком-то промежуточном формате и сразу писать код, но это менее удобно.
Для того, чтобы эффективно использовать GraphQL, неплохо бы уметь параллельно опрашивать источники данных. В PHP есть разные способы для этого, но все они, так или иначе, имеют проблемы. Поэтому наш выбор пал на JSON API — её гибкости достаточно для наших клиентов, а реализация на бэке не требует костылей.
Время на «сделать запрос» можно разделить на две составляющие: это время, которое будет потрачено на установление соединение, и время, которое нужно серверному приложению для бутстрапа. Первой составляющей, в общем-то, отчасти можно принебречь, поскольку HTTP/2 поддерживает мультиплексацию, упаковывая несколько запросов в одно соединение.
Так вот, если время, которое приложение потратит на генерацию ответа клиенту, сравнимо с временем, потраченным на сетевое взаимодействие и бутстрап (скажем, API достаёт уже подготовленный ответ из кеша), правда на вашей стороне.
Однако, если получение запрошенных коллекций требует выполнения какой-то сложной бизнес-логики, ситуация перестаёт быть такой однозначной, и тут вполне может выиграть распараллеливание запросов.
Разумеется, есть сложные случаи, когда одна модель должна распасться на несколько сущностей, или, напротив, одна сущность состоит из нескольких моделей — но такие кейсы мы умеем обрабатывать.
Не могли бы вы рассказать в общих чертах, как вы выполняете обратную трансформацию?
Ну и про отказ от бэкенда я вас, честно говоря, не понял :)
Я вижу тут два варианта:
Получается, что запрос клиента обрабатывается GraphQL-сервером на Node, который отправляет запросы к PHP-бекенду, объединяет ответы и отдаёт результат клиенту обратно. В таком подходе лично мне не нравится наличие промежуточного слоя (Node), и, кроме того, есть ощущение, что со временем бизнес-логика начнёт размазываться по JS и PHP.
1. Ну, спека-то, всё же, не наша. Смею предположить, что в момент перехода на JSON API вменяемой имплементации GraphQL на PHP не было. Однако, даже если я не прав, в GraphQL смущает другое: параллельное получение данных из разных источников на PHP хоть и возможно, но не без костылей.
2. Вариант с билдером показался более универсальным.
3. Swagger-UI.
Тем не менее, любопытно, на каких платформах вы используете protobuf?