Зачем нужен GraphQL
Чтобы ответить на этот вопрос, нужно сказать пару слов об архитектуре REST API. Сегодня этот инструмент повсеместно используется для связи фронтенда и бэкенда. Когда пользователь сайта нажимает на кнопку на сайте, скажем, переходит на страницу в интернет-магазине, за передачу данных с сервера вероятнее всего отвечает именно REST (по крайней мере, если используется технология SPA).
В REST API под каждый набор данных предоставляется своя конечная точка (endpoint), к каждой из которых нужно обращаться по отдельности. Часто это порождает структурные проблемы: недостаточную, или напротив, избыточную передачу данных. Взаимодействие между клиентом и сервером строится на согласованности между разработчиками: фронтендом (FE), и бэкендом (BE). При таком подходе документация может не соответствовать реальности — это бывает редко, но больно.
REST часто называют архитектурным стилем организации работы с серверами, никаких единых стандартов тут нет. По сути это согласованный набор решений и ограничений для организации системы. Стоит ли говорить, что такой подход порождает ряд сложностей в разработке и поддержке проектов? Вести документацию в REST приходится в ручном режиме, а синхронизация между разработчиками иногда работает в формате устных договоренностей.
Если проект выдался большим и сложным, либо логика конечных точек в REST прописана неудачно, то это создает дополнительную нагрузку и сложности в работе всей системы.
• • •
Слишком часто разработчикам приходится изобретать велосипед, продумывая наперед решение еще ненаступивших проблем, писать лишний код. В итоге цикл разработки затягивается, а уровень технического исполнения проекта падает.
Разница между GraphQL и REST на примере бургера
Мы в конечном итоге суммировали минусы REST API так:
- отсутствие единой спецификации;
- структурные проблемы (недостаточная или избыточная выборка);
- раздутый код веб-платформы;
- нестабильность и отсутствие типизации API.
GraphQL родился как способ решения этих проблем. Его конечная цель — стандартизация передачи данных между фронтендом и бэкендом. Достаточно сказать, что этот язык создали в Facebook, потому что намучились с организацией обслуживания миллионов запросов к серверам самой большой соцсети в мире.
С точки зрения бэкенда
Для BE-разоработчиков работа с документацией в REST может быть действительно мучительным занятием. Инструментов для простой поддержки документации практически нет. Разработчик может сгенерировать базовую документацию. Но в конце концов приходится вносить изменения и пояснения вручную, так как из-за отсутствия стандартов REST API какого-то специализированного генератора нет.
«Поддержка актуальности документации — это боль для бэкендера, всегда. Поддерживать документацию сложно, особенно если BE и FE не находятся в одном помещении, и фронтэндер не может спросить бэкендера по поводу какой-то проблемы, отсутствующего поля или еще чего-то. Это вредит работе. Если они находятся на расстоянии и могут созвониться, то фронтэндер обычно просит актуализировать документацию. Соответственно, работа останавливается, бэкендер идет работать с документацией», — поясняет наш бэкэнд-разработчик Сергей.
В случае GraphQL генерация документации неразрывно связана с кодингом. Можно писать код, а под него будет автоматически формироваться схема и документация (принцип code first). Можно описать схему, и под нее делать код (принцип scheme first). В любом случае в GraphQL обязательно наличие и того, и другого. Схема формируется автоматически. Если поле, тип или запрос меняются, меняется и содержание документов.
На практике автогенерация все же может привести к неожиданным проблемам на стороне фронтенда. Тогда в бэкенд летят камни, но фронтендер может быстро разобраться в проблеме, открыв документацию. Схема по умолчанию будет актуальной.
Разработчикам всегда не очень приятно заниматься правками и изменениями уже написанного, особенно если речь идет о чужом коде. Конечно, GraphQL тоже не позволяет полностью этого избежать. Даже если актуализировать саму документацию не требуется, нужно по необходимости менять данные, как и в REST. Но в целом, автогенерация работает и экономит массу времени. Разработка и поддержка проектов на GraphQL требует гораздо меньше сил и нервов, продвигается быстрее и по итогу стоит дешевле.
С точки зрения фронтенда
В ограничениях REST API фронтенд и мобайл-разработчикам приходится очень тщательно оценивать все свои планы. Нужно уметь смотреть на проект глазами бэкендеров, предугадывать сложности.
Отдельный слой API во многом освобождает FE-разработчика от тревоги, позволяет сосредоточиться на продукте, а не на его возможных проблемах (которые могут возникнуть, а могут и не возникнуть).
GraphQL позволяет разделить клиентскую и серверную разработки, команда фронтенда может работать с должным уровнем независимости, если знает структуру данных. Недоразумения и войны между бэком, веб- и мобайл-разработчиками уходят в прошлое.
«Если решить изначально все вопросы по организации кода, то потом мы получаем большой буст при разработке в больших проектах. В работе исчезает куча лишних итераций, потому что раньше временами доходило даже до каких-то дурацких бюрократических процессов, особенно если в разработку вовлечена третья сторона. Мы теперь с фронта можем решить любую задачу, даже не затрагивая бэкенд, главное чтобы они в GraphQL подготовили все типы, которые нужны, а мы уже набираем в зависимости от ситуации. И это очень сильно нас ускоряет», — рассказал наш фронтенд-разработчик Олег.
Техническая реализация GraphQL предполагает, что все данные описываются путем определения типов и полей этих типов. Организация запросов похожа на шведский стол из данных. Можно не плодить лишние эндпоинты, веб и мобайл могут набрать все, что им нужно, за один запрос. Решаются проблемы выборки, приходит избавление от овер- и андерфетчинга.
GraphQL дает FE-разработчикам и другие технические преимущества: статическую типизацию схем данных и автогенерацию интерфейсов. При должном освоении возможностей языка объем рукописного кода на фронте уменьшается в разы.
Сегодня GraphQL уже не писк моды или какая-то экзотика. Он оброс массой полезных библиотек, его можно без проблем интегрировать со всеми популярными языками программирования и фреймворками. В качестве недостатка можно упомянуть отсутствие HTTP-кэширования и HTTP-заголовков с кодами ответа, но использование фреймворка GraphQL компенсирует этот недостаток.
Сложности GraphQL
Сегодня единственный существенный недостаток, на который обращают внимание наши BE-разработчики — это производительность маппинга при выдаче данных. Если в REST данные, которые передаются на фронтенд, преобразуются в простые JSON-объекты, то в случае с GraphQL все иначе. Данные еще на стороне сервера поступают на преобразование в resolver, а он преобразует их в схему, которую запросил фронт — то есть проводит маппинг данных.
В GraphQL фронтенд может запрашивать на сервере лишь нужные ему определенные поля (скажем, два из 10 полей объекта User: его ID и Username). Это очень удобно: запрос свободен от излишних данных. Меньше данных запрошено, меньше данных получено — в этой схеме все происходит быстрее.
Но когда данные отдаются бэкендом, они проверяются на наличие конкретных полей (к примеру, что это поле not null
) или на лишние поля, которые надо исключить из запроса. И вот этот момент создает дополнительную нагрузку на систему.
«Грубо говоря, если мы работаем с REST, если мы берем какие-то большие данные (переводы, например), у нас ответ идет в рамках 50 миллисекунд, то в рамках GraphQL на это может уйти до 100 миллисекунд — время на вот этот маппинг», — пояснил разработчик.
В высоконагруженных проектах использование REST API может быть более оправданным. Если фронтенд будет выполнять намного больше запросов, и отдача данных должна идти быстрее, то REST API будет смотреться выигрышнее. Но в таких случаях можно рассмотреть еще и веб-сокеты, позволяющие отдавать данные еще быстрее. При этом есть сокеты как для REST, так и для GraphQL.
Каждый, кто работал с GraphQL, наслышан о пресловутой проблеме N+1 запросов, которая может создать дополнительную нагрузку на базу данных при работе с большими выборками. На сегодня она подробно описана и закрыта загрузчиками данных, хотя бывают и поистине уникальные случаи, требующие отдельного анализа.
На практике производительность конкретного проекта состоит из целого ряда переменных:
- доступные серверные мощности;
- количество инстансов;
- используемые языки программирования и фреймворков.
«Я вообще сторонник оптимального использования ресурсов. Если проект будет высоконагруженным, все равно нужно над этим думать. Есть удобство разработки, есть скорость работы. GraphQL решает проблемы удобства разработки. На многих языках, на многих фреймворках, GraphQL работает не хуже, чем REST. Там маппинг — проблема, которая может снижать производительность на 2-3%», — отмечает наш бэкенд-разработчик Сергей.
Из практики в рамках Laravel и пакета Rebing использование GraphQL дает оптимальный результат. У нас это обычная связка для относительно небольших проектов, таких как закрытые CRM-системы.
Совсем иная сложность GraphQL — более высокий порог вхождения для специалистов.
Тем, кто давно привык работать с REST, нужно научиться мыслить по-новому. Тем, кто ранее не имел дела с типизированными языками, тоже поначалу будет непросто.
• • •
Но это обычная проблема нехватки опыта работы с новой технологией, и она постепенно будет изжита. Остается лишь «лупати сю скалу», как завещал украинский классик Иван Франко. С каждым новым нашим проектом сложностей вокруг GraphQL становится все меньше, зато преимущества выходят на первый план.
Опыт разработки
Первым нашим большим проектом на GraphQL стал портал корпорации-застройщика «Риел». Это целая инфраструктура из нескольких сайтов, с мультиадминкой и сквозным личным кабинетом пользователя — покупателя недвижимости. Организация логики запросов через REST в такой обширной системе представлялась затруднительной, но реализованный через GraphQL дополнительный слой API тут вписался идеально.
Наши команды начали активно применять технологию в новых проектах. Стало ясно, что гибкость и эффективность GraphQL хорошо отвечает нашим запросам, хотя и требует более высокой квалификации. Еще год назад старт проекта с этой технологией требовал от нас значительной раскачки, но все меняется. Разработчики готовят архитектурные шаблоны под будущие проекты.
«Сейчас мы делаем “сырье” — прямо “болванки”, в которых заключена основа, и это нам позволяет ускорять разработку проектов, потому что мы уменьшаем всякие нулевые спринты, когда мы настраиваем все, и так далее. Мы работаем над тем, чтобы составить какие-то сырые наработки, материалы, и самое главное — сделать из них архитектуру. Это как сделать нарезку для салата, и когда понадобится, просто его собрать. Большое отличие GraphQL от REST API — то, что это уже спецификация, это целый язык, и эту спецификацию, эти схемы можно описать», — объяснил наш фронтенд-разработчик Олег.
Бэкенд при этом может реализовывать схему на любом языке. Разработчики WEZOM сейчас используют php, но переходят на Java, и сами схемы от этого никак не меняются.
Что же в итоге?
Конечно, GraphQL — не панацея от всех бед. Использование этого языка не всегда оправдано как по соображениям производительности, так и с точки зрения инвестиций в разработку. При создании небольшого и быстрого сайта такой инструмент будет избыточным. И это точно не лучший выбор для малочисленных команд или вольных фулстек-разработчиков. Важно помнить, что риск наломать дров в GraphQL гораздо выше, чем в REST — тут нужна крупная и опытная команда, способная свести риски производительности к минимуму.
GraphQL никогда не заменит и не вытеснит REST — это все равно, что представить себе, как поезда вытесняют из нашей жизни автомобили.
• • •
На REST по-прежнему будут создаваться и поддерживаться успешные проекты, даже достаточно крупные. Но в части разработки оригинальных и масштабных проектов у GraphQL на сегодня конкурентов нет. Два года наших опытов с технологией доказали, что все муки роста и сложности миграции стоили того. No pain, no gain.