Что такое GraphQL и в чем его ключевые отличия от REST

Ответ

GraphQL — это язык запросов для API и среда выполнения для обработки этих запросов с использованием существующих данных. Он позволяет клиенту точно указать, какие данные ему нужны.

Ключевые отличия от REST:

Аспект REST GraphQL
Эндпоинты Множество эндпоинтов для разных ресурсов (/users, /posts) Обычно один эндпоинт (/graphql) для всех запросов
Получение данных Структура ответа определяется сервером. Часто приводит к over-fetching (получение лишних данных) или under-fetching (необходимость делать доп. запросы) Клиент запрашивает только нужные поля, получая предсказуемый результат
Типизация Не встроена в стандарт. Используются внешние спецификации, например, OpenAPI (Swagger) Строгая система типов встроена в схему (Schema Definition Language, SDL), что обеспечивает самодокументируемость API
HTTP-методы Использует разные методы (GET, POST, PUT, DELETE) для разных операций В основном использует POST для всех операций (включая чтение)

Проблема N+1 в GraphQL

Это распространенная проблема, когда для получения списка из N элементов и их связанных данных выполняется N+1 запрос к базе данных. Она решается с помощью паттерна Dataloader, который группирует множество запросов в один пакетный запрос.

Пример простого GraphQL-сервера (Python/Graphene):

import graphene
from flask import Flask
from flask_graphql import GraphQLView

# Определение схемы: какие запросы (Query) может выполнять клиент
class Query(graphene.ObjectType):
    hello = graphene.String(name=graphene.String(default_value="World"))

    # Функция-резолвер, которая возвращает данные для поля 'hello'
    def resolve_hello(self, info, name):
        return f"Hello, {name}!"

schema = graphene.Schema(query=Query)

app = Flask(__name__)
app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, graphiql=True))

if __name__ == '__main__':
    app.run()

Когда использовать GraphQL?

  • Когда у вас много разных клиентов (веб, мобильные) с разными требованиями к данным.
  • В сложных системах со множеством связанных сущностей.

Ответ 18+ 🔞

Слушай, а GraphQL — это, блядь, такая штука, когда ты можешь API попросить: «Дай мне вот это, это и вот то, но без всего остального, нахуй». И он тебе выдаёт ровно то, что ты просил, без лишней хуйни. Не то что REST, сука, где тебе прилетает целый вагон данных, а нужного-то поля и нет, приходится ещё пять запросов делать, пиздец просто.

Чем он от REST отличается, если по-простому:

Что сравниваем REST (старая школа) GraphQL (умный пацан)
Точки входа Куча разных адресов: /users, /posts, /comments — запомни их все, блядь. Одна точка, обычно /graphql, и там уже разберёмся, что тебе надо.
Что прилетает в ответ Сервер решает, какую портянку тебе отправить. Часто получаешь кучу ненужного (over-fetching) или, наоборот, не хватает (under-fetching), приходится опять стучаться. Ты сам говоришь, какие поля хочешь. Хочешь только имя и почту — получишь только их. Красота, ёпта!
Типы данных В стандарте типов нет, приходится Swagger смотреть, если повезёт. Всё строго описано в схеме, самодокументируется. Открыл — и видишь, что можно запросить.
Методы HTTP GET, POST, PUT, DELETE — танцы с бубном. В основном POST на все случаи жизни, даже для чтения. Ну, так исторически сложилось.

А ещё есть проблема N+1, ебать как бесит!

Представь: запрашиваешь список из 10 пользователей и для каждого ещё его посты. Без оптимизации сделаешь 1 запрос за пользователями и потом ещё 10 отдельных за постами — вот тебе и N+1, пиздец производительности. Лечится это Dataloader'ом — он кучу мелких запросов собирает в один здоровенный и бабахает в базу. Волшебство, блядь!

Вот тебе кусочек кода на Python (Graphene), чтоб понятнее было:

import graphene
from flask import Flask
from flask_graphql import GraphQLView

# Описываем, что можно спросить у API
class Query(graphene.ObjectType):
    hello = graphene.String(name=graphene.String(default_value="World"))

    # Это резолвер — функция, которая реально данные достаёт
    def resolve_hello(self, info, name):
        return f"Hello, {name}!"

schema = graphene.Schema(query=Query)

app = Flask(__name__)
app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, graphiql=True))

if __name__ == '__main__':
    app.run()

Когда его использовать, а?

  • Когда у тебя куча разных клиентов: один с телефона хочет минимум данных, другой с веба — всё подряд, третий вообще какую-то свою комбинацию запрашивает. GraphQL тут — спасение, блядь.
  • В сложных системах, где всё связано: пользователи, заказы, комментарии, теги... Один запрос решит всё, а не 20 разных на каждый чих.

Короче, если над REST'ом уже плакать хочется от количества костылей — присмотрись к GraphQL. Он, конечно, не серебряная пуля, но часто реально жизнь упрощает, ёпта!