Перевод статьи Sashko Stubailo GraphQL vs. REST

Два способа отправки данных по протоколу HTTP: в чем разница?


GraphQL часто представляют как революционно новый путь осмысления API. Вместо работы с жестко определенными на сервере конечными точками (endpoints) вы можете с помощью одного запроса получить именно те данные, которые вам нужны. И да — GraphQL гибок при внедрении в организации, он делает совместную работу команд frontend- и backend-разработки гладкой, как никогда раньше. Однако на практике обе эти технологии подразумевают отправку HTTP-запроса и получение какого-то результата, и внутри GraphQL встроено множество элементов из модели REST.


Так в чем же на самом деле разница на техническом уровне? В чем сходства и различия между этими двумя парадигмами API? К концу статьи я покажу вам, что GraphQL и REST отличаются не так уж сильно, но у GraphQL есть небольшие отличия, которые существенно меняют процесс построения и использования API разработчиками.


Так что давайте сразу к делу. Мы определим некоторые свойства API, а затем обсудим, как они реализованы в GraphQL и REST.

Ресурсы


Ключевое для REST понятие — ресурс. Каждый ресурс идентифицируется по его URL, и для получения ресурса надо отправить GET-запрос к этому URL. Скорее всего, ответ придет в формате JSON, так как именно этот формат используется сейчас в большинстве API. Выглядит это примерно так:


GET /books/1
{
  "title": "Блюз черных дыр и другие мелодии космоса",
  "author": { 
    "firstName": "Жанна",
    "lastName": "Левин"
  }
  // ... другие поля
}

Замечание: для рассмотренного выше примера некоторые REST API могут возвращать данные об авторе (поле «author») как отдельный ресурс.


Одна из заметных особенностей REST состоит в том, что тип, или форма ресурса, и способ получения ресурса сцеплены воедино. Говоря о рассмотренном выше примере в документации по REST API, вы можете сослаться на него как на «book endpoint».


GraphQL весьма отличается в этом аспекте, потому что в GraphQL эти два понятия полностью отделены друг от друга. В вашей схеме может быть два типа, Book и Author:


type Book {
  id: ID
  title: String
  published: Date
  price: String
  author: Author
}

type Author {
  id: ID
  firstName: String
  lastName: String
  books: [Book]
}

Заметьте: мы описали типы доступных нам данных, но это описание совершенно ничего не говорит вам о том, как эти объекты могут быть извлечены клиентом. Это одно из ключевых различий между REST и GraphQL?: описание отдельного ресурса не связано со способом его получения.


Чтобы действительно получить доступ к отдельно взятой книге или автору, нам понадобится создать тип Query в нашей схеме:


type Query {
  book(id: ID!): Book
  author(id: ID!): Author
}

Теперь мы можем отправить запрос, аналогичный REST-запросу, рассмотренному выше, но на этот раз с помощью GraphQL:


GET /graphql?query={ book(id: "1") { title, author { firstName } } }

{
  "title": "Блюз черных дыр и другие мелодии космоса",
  "author": {
    "firstName": "Жанна",
  }
}

Отлично, это уже что-то! Мы немедленно видим несколько особенностей GraphQL, весьма отличающих его от REST, даже несмотря на то, что оба они могут быть запрошены через URL, и оба могут вернуть одну и ту же форму JSON-ответа.


Прежде всего, мы видим, что в GraphQL-запросе URL содержит как нужный нам ресурс, так и описание интересующих нас полей. Кроме того, уже не разработчик сервера решает за нас, что нужно включить в ответ связанный ресурс author, — это теперь решение клиента, использующего API.


Но, что более важно, сущности ресурсов, понятия Books и Authors, не привязаны к способу их извлечения. Мы могли бы извечь одну и ту же книгу с помощью запросов различного типа и с различным набором полей.


Выводы


Мы уже обнаружили некоторые сходства и различия:


  • Сходство: есть понятие ресурса, есть возможность назначать идентификаторы для ресурсов.
  • Сходство: ресурсы могут быть извлечены с помощью GET-запроса URL-адреса по HTTP.
  • Сходство: ответ на запрос может возвращать данные в формате JSON.
  • Различие: в REST вызываемая вами конечная точка (endpoint) — это и есть сущность объекта. В GraphQL сущность объекта отделена от того, как именно вы его получаете.
  • Различие: в REST структура и объем ресурса определяются сервером. В GraphQL сервер определяет набор доступных ресурсов, а клиент указывает необходимые ему данные прямо в запросе.

Если вы уже использовали GraphQL и/или REST, пока все было довольно просто. Если раньше вы не использовали GraphQL, можете поиграть на Launchpad с примером, подобным приведенному выше.


URL-маршруты и схемы GraphQL


API бесполезен, если он непредсказуем. Когда вы используете API, вы обычно делаете это в рамках какой-то программы, и этой программе нужно знать, что она может вызвать и что ей ожидать в качестве результата такого вызова, чтобы этот результат мог быть обработан программой.


Итак, одна из важнейших частей API — это описание того, к чему возможен доступ. Это как раз то, что вы изучаете, читая документацию по API, а с помощью GraphQL-интроспекции или систем поддержки схем REST API вроде Swagger эта информация может быть получена прямо из программы.


В существующих сегодня REST API чаще всего API описывается как список конечных точек (endpoints):


GET /books/:id
GET /authors/:id
GET /books/:id/comments
POST /books/:id/comments

Можно сказать, что «форма» API линейна — это просто список доступных вам вещей. При извлечении данных или сохранении какой-либо информации первый вопрос, который вы задаете себе: «Какой endpoint мне следует вызвать»?


В GraphQL, как мы разобрались ранее, вы не используете URL-адреса для идентификации того, что вам доступно в API. Вместо этого вы используете GraphQL-схему:


type Query {
  book(id: ID!): Book
  author(id: ID!): Author
}

type Mutation {
  addComment(input: AddCommentInput): Comment
}

type Book { ... }
type Author { ... }
type Comment { ... }
input AddCommentInput { ... }

Здесь есть несколько интересных особенностей по сравнению с маршрутами REST для аналогичного набора данных. Первое: вместо выполнения HTTP-запросов одного и того же URL-адреса с помощью разных методов (GET, PUT, DELETE и т.п.) GraphQL использует для различения чтения и записи разный начальный тип ?— ?Mutation или Query. В GraphQL-документе вы можете выбрать, какой тип операции вы отправляете, с помощью соответствующего ключевого слова:


query { ... }
mutation { ... }

Более детально язык запросов разбирается в более ранней моей статье «Анатомия запросов GraphQL» (англ.), перевод на Хабрахабре.


Как видите, поля типа Query довольно хорошо совпадают с маршрутами REST, рассмотренными выше. Это потому, что данный специальный тип является входной точкой для доступа к нашим данным, так что в GraphQL это наиболее близкий эквивалент понятию «URL конечной точки (endpoint URL)».


Способ получения начального ресурса от GraphQL API довольно похож на то, как это делается в REST: вы передаете имя и некоторые параметры; но главное отличие здесь в том, куда вы сможете двинуться после этого. В GraphQL вы можете отправить сложный запрос, который извлечет дополнительные данные согласно связям, определенным в схеме, а в REST вам для этого пришлось бы сделать несколько запросов, встроить связанные данные в начальный запрос, или же включить какие-то особые параметры в URL-запрос для модификации ответа.


Выводы


В REST пространство доступных данных описывается как линейный список конечных точек (endpoints), а в GraphQL это схема со связями между ее элементами.


  • Сходство: список конечных точек в REST API похож на список полей в типах Query и Mutation, используемых в GraphQL API. Оба они являются точками входа для доступа к данным.
  • Сходство: есть возможность различать запросы к API на чтение и на запись данных.
  • Различие: в GraphQL вы можете внутри одиночного запроса перемещаться от точки входа к связанным данным, следуя связям, определенным в схеме. В REST для получения связанных ресурсов вам придется выполнить запросы к нескольким конечным точкам.
  • Различие: в GraphQL нет разницы между полями типа Query и полями любого другого типа, за исключением того, что в корне запроса доступен только тип query. Например, у вас в запросе любое поле может иметь аргументы. В REST не существует понятия первого класса в случае вложенного URL.
  • Различие: в REST вы определяете запись данных, меняя HTTP-метод запроса с GET на что-то вроде POST. В GraphQL вы меняете ключевое слово в запросе.

Из-за первого пункта в списке сходств, указанных выше, люди часто начинают воспринимать поля типа Query как «конечные точки» или «запросы» GraphQL. Хотя такое сравнение и имеет определенный смысл, оно может привести к искаженному восприятию, будто тип Query работает совершенно иначе, чем другие типы, а это совсем не так.


Обработчики маршрутов и распознаватели


Итак, что происходит, когда вы вызываете API? Ну, обычно при этом на сервере выполняется какой-то код, получивший ваш запрос. Этот код может выполнять расчеты, загружать данные из базы, вызывать другой API, и вообще делать все, что угодно. Весь смысл в том, что вам снаружи нет необходимости знать, что именно делает этот код. Но и в REST, и в GraphQL есть стандартные способы реализации внутренней части API, и будет полезно сравнить их для понимания того, насколько различны эти технологии.


В этом сравнении я буду использовать код на JavaScript, потому что я знаю этот язык лучше всего, но вы, конечно же, можете использовать практически любой язык программирования для реализации и REST, и GraphQL API. Я также пропущу все подготовительные этапы, требуемые для поднятия и запуска сервера, потому что это не важно для рассматриваемых вопросов.


Рассмотрим пример реализации «Hello World» с помощью express, популярного фреймворка для построения API на Node:


app.get('/hello', function (req, res) {
  res.send('Hello World!')
})

Как видите, мы создали конечную точку /hello, которая возвращает строку 'Hello World!'. Из этого примера становится понятен жизненный цикл HTTP-запроса на сервере REST API:


  1. Сервер получает запрос и извлекает HTTP-метод (в нашем случае GET) и путь URL
  2. API-фреймворк сопоставляет метод и путь с функцией, зарегистрированной в серверном коде
  3. Функция выполняется один раз и возвращает результат
  4. API-фреймворк преобразует результат, добавляет соответствующие код и заголовки ответа и отправляет все это обратно клиенту

GraphQL работает очень похожим способом, и для того же примера код практически тот же самый:


const resolvers = {
  Query: {
    hello: () => {
      return 'Hello world!';
    },
  },
};

Как видите, вместо предоставления функции для выбранного URL мы указываем функцию, которая сопоставляет отдельное поле типу, в нашем случае — поле hello типу Query. В GraphQL функция, реализующая такое сопоставление, называется распознавателем (resolver).


Чтобы получить данные, нам нужен запрос (query):


query {
  hello
}

Итак, что происходит, когда наш сервер получает GraphQL-запрос:


  1. Сервер получает HTTP-запрос и извлекает из него GraphQL-запрос
  2. Запрос (query) проходится насквозь, и для каждого поля вызывается соответствующий распознаватель (resolver). В нашем случае поле всего одно, hello, и ему соответствует тип Query.
  3. Функция вызывается и возвращает результат
  4. Библиотека GraphQL и сервер прикрепляют полученный результат к ответу, который соответствует форме запроса (query)

Вы получаете от сервера ответ:



{ "hello": "Hello, world!" }

Но есть один трюк: мы можем вызвать одно поле дважды!


query {
  hello
  secondHello: hello
}

В этом случае цикл обработки тот же, но так как мы запросили одно и то же поле дважды (используя псевдоним), распознаватель hello на самом деле будет вызван дважды. Пример соврешенно надуманный, но смысл в том, что множество полей могут выполняться в рамках одного запроса, а одно и то же поле может вызываться множество раз в разных местах запроса.


Объяснение не было бы полным без примера с вложенными распознавателями («nested» resolvers):


{
  Query: {
    author: (root, { id }) => find(authors, { id: id }),
  },
  Author: {
    posts: (author) => filter(posts, { authorId: author.id }),
  },
}

Эти распознаватели способны разрешить запрос вроде такого:


query {
  author(id: 1) {
    firstName
    posts {
      title
    }
  }
}

Итак, хотя список распознавателей на самом деле плоский, из-за прикрепления их к различным типам вы можете построить из них вложенные запросы. Подробнее о том, как работает выполнение GraphQL, читайте в статье «GraphQL Explained».


Можете посмотреть полный пример и протестировать его, запуская разные запросы!




Художественная интерпретация извлечения ресурсов: в REST множество данных гоняются туда и обратно, в GraphQL все делается одним-единственным запросом


Выводы


На настоящий момент как REST, так и GraphQL API являются лишь причудливыми способами вызывать функции по сети. Если вам знакомо построение REST API, реализация GraphQL API не будет особо отличаться. Однако GraphQL имеет большое преимущество: возможность вызова нескольких взаимосвязанных функций в рамках одного запроса.


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

По сути, вы можете думать о GraphQL как о системе для вызова множества вложенных конечных точек в одном запросе. Почти как мультиплексированный REST.


Что все это значит?


Есть множество тем, на которые в данной статье не хватило места. Например, идентификация объектов, гипермедиа или кэширование. Возможно, это станет темой одной из следующих статей. Я надеюсь, теперь вы согласитесь, что если взглянуть на основные принципы, то окажется, что REST и GraphQL работают с понятиями, которые принципиально очень похожи.


Я думаю, некоторые из различий говорят в пользу GraphQL. В частности, мне кажется, действительно здорово иметь возможность реализовать свой API как набор небольших функций-распознавателей, а затем отправлять сложные запросы, которые предсказуемым способом извлекают множество ресурсов за один раз. Это ограждает разработчика API от необходимости создавать множество конечных точек с различной формой, а клиенту API позволяет избежать извлечения лишних данных, которые ему не нужны.


С другой стороны, для GraphQL пока нет такого множества инструментов и решений по интеграции, как для REST. Например, у вас не получится с помощью HTTP-кэширования кэшировать результаты работы GraphQL API так же легко, как это делается для результатов работы REST API. Однако сообщество упорно работает над улучшением инструментов и инфраструктуры, а для кэширования GraphQL вы можете использовать такие инструменты, как Apollo Client и Relay.


Если у вас есть еще мысли по поводу различий между REST и GraphQL — высказывайтесь в комментариях.

Комментарии (279)


  1. begemot_sun
    08.08.2017 13:28
    +8

    Т.е. вместо того чтобы отталкиваться от предметной области задачи, требований к данным со стороны клиента.
    люди постоянно придумывают себе границы в виде каких-то REST API или GraphQL, которые вместо того чтобы помогать, на самом деле только ограничивают гибкость.
    Что мешает думать о HTTP API как об интерфейсе команда-результат, где не обязательно наличие каких-то осмысленных ресурсов, CRUD и т.п. операций.
    Зачем это всё?


    1. serf
      08.08.2017 13:39
      +3

      как об интерфейсе команда-результат

      Ну вот GraphQL как раз ближе гораздо к этому чем REST API. Один ендплоинт куда отправляешь запросы на выборку только необходимых данных или на обновление данных. То есть оперируешь сущностями подобно таблицами в SQL (строя связи в запросах), а не ендпоинтами которые повешаны поверх сущностей в случае REST API.


      PS вообще подобный OData стандарт существовал до GraphQL.


      1. begemot_sun
        08.08.2017 13:50
        +3

        Все это хорошо, но не жизнеспособно. Т.к. любой API между сервером и клиентом является публичным, т.о.
        им может воспользоваться злоумышленник.

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

        По аналогии с SQL, если вы откроете доступ к БД, то злоумышленник может сделать SQL запрос с кучей join которые тупо повесят ваш сервер БД (вам же это не хочется, правда ?). Разве сам по себе GraphQL может защитить от такой участи? Я думаю нет, а раз нет — то зачем это всё нужно?


        1. zelenin
          08.08.2017 14:12

          а БД как решает проблему кучи джойнов? И почему GraphQL ее должен решать, если это не его задача?


          1. begemot_sun
            08.08.2017 14:17

            А вы выставляете БД в мир и говорите, приди сюда плохой человек, я дам своему хостеру 100500 денег на твой запрос?

            GraphQL — решение для публичного API, поэтому он должен решать этот вопрос. Иначе грош цена дырявому интерфейсу.


            1. zelenin
              08.08.2017 14:24
              +2

              А вы выставляете БД в мир и говорите, приди сюда плохой человек, я дам своему хостеру 100500 денег на твой запрос?

              нет, конечно. Я, как разработчик api, и в graphql не дам выполнять все что душе угодно.


              GraphQL — решение для публичного API, поэтому он должен решать этот вопрос. Иначе грош цена дырявому интерфейсу.

              graphql — это спецификация клиентского апи, и не описывает серверную реализацию от слова "совсем". Так же как спецификация языка sql не описывает реализацию базы данных и защиту от множественных джойнов.


              1. begemot_sun
                08.08.2017 14:35

                Ваш сервер либо соотвествует спецификации и тогда это GraphQL сервер, либо нет.
                > нет, конечно. Я, как разработчик api, и в graphql не дам выполнять все что душе угодно.
                ну т.е. мы пошли в софизмы и теперь говорим что где-то мы поддерживаем GraphQL, а где-то нет.
                Значит вы делаете не GraphQL сервер.

                Мой вопрос состоит в том, как из самого запроса понять его сложность? Понять насколько он сложен для машины, и вовремя его отбросить чтобы заняться чем-то другим. Есть решения этого вопроса?
                Когда вы делаете SQL-запрос, сервер обязан отдать вам результат и он его ищет.
                Когда вы делаете GraphQL запрос, вы вольны делать что угодно. Но опять же в случае какого либо RPC (как выше назвали этот подход), это позволяет контроллировать все аспекты взаимодействия. И т.о. даже если клиент генерирует вредоносные для сервера запросы, сервер может их просто игнорировать используя простые правила фильтрации.
                В случае GraphQL, эта спецификация дает бесконечное множество путей получения данных.
                И мой вопрос состоит в том, каким образом это множество можно ограничить до разумных пределов, чтобы контроллировать производительность сервера и «хорошие намерения» клиента.
                Вопрос понятен?


                1. zelenin
                  08.08.2017 14:40

                  И мой вопрос состоит в том, каким образом это множество можно ограничить до разумных пределов, чтобы контроллировать производительность сервера и «хорошие намерения» клиента.

                  даже если клиент генерирует вредоносные для сервера запросы, он может их просто игнорировать используя простые правила фильтрации

                  все аналогично. Спецификация описывает язык запросов, а не бесконечную вложенность или сотни методов получения.


                  1. begemot_sun
                    08.08.2017 14:50

                    Спецификация — это спецификация. Таким же макаром можно поддреживать ограниченный SQL и все тоже самое будет. Меня интересует вопрос более общего плана.
                    В случае RPC мы каждой команде можем сопоставить однозначную стоимость её выполения, причем сделать это заранее.
                    Когда за единицу времени клиент генерирует слишком большую стоимость, мы можем его игнорировать.
                    Теперь возьмем «универсальный интерфейс», которые позволяет нам генерить кучу запросов, и получать данные даже такие, которые разработчик интерфейса и не думал что они будут запрошены.
                    Мой вопрос состоит в том, как из самого запроса получить стоимость его выполнения?
                    В случае RPC всё просто, в случае GraphQL всё неоднозначно. Пока не выполнилнишь, не поймешь. Т.о. этот универсальный путь открывает такие очень хорошие возможности по «нагружанию» вашего сервера. А зачем оно вам вообще это надо?


                    1. zelenin
                      08.08.2017 15:08
                      +1

                      В случае RPC всё просто, в случае GraphQL всё неоднозначно.

                      на самом деле ни в первом ни во втором случае не все так, как вы говорите. Необязательно стоимость запроса известна заранее, если RPC поддерживает вложенность ответа (а RPC это не оговаривает), и необязательно стоимость заранее неизвестна при работе с GraphQL, если сервер позволяет запрашивать сущности 1-2 вложенностей максимум, без рекурсии (реализацию GraphQL тоже не оговаривает).
                      Это все детали реализаций — вложенность, рекурсия, rate limiting, security, authorization/authentification итд. Сама спека только о языке запросов.


                      1. napa3um
                        08.08.2017 18:25

                        Накрутив на GraphQL-сервер контроль вложенности, рекурсии, rate limiting, security, authorization/authentification и т.д. получится REST-API с чётким разделением ресурсов. GraphQL — это просто «ленивое» проектирование (REST-подход «заставляет» планировать иерархию ресурсов и ограничений чуть раньше, чем GraphQL), вступающее в конфликт с идеологией веба и всего промежуточного ПО (помимо контроля доступа к данным и нагрузки на сервер GraphQL кладёт большой болт на кеширование). Больше принципиальных отличий между этими двумя подходами в построении API нет.


                        1. zelenin
                          08.08.2017 18:40

                          принципиальное отличие — это эндпойнты снаружи у rest и ресолверы внутри у graphql. Кладет или не кладет болт graphql на все точно так же, как и rest.
                          Весь "обвес" — это атрибуты любого апи, и они не сделают из graphql rest или наоборот. Они банально работают на другом уровне.


                          1. napa3um
                            08.08.2017 18:48
                            +1

                            Да, GraphQL прячет резолверы ресурсов внутрь, делая бесполезными коды ошибок HTTP, глаголы HTTP, заголовки HTTP, используемые промежуточным ПО для кеширования и контроля работы с данными. Именно об этом я и говорю, GraphQL — это «ленивое» проектирование, которое удешевляет разработку на старте проекта, но удорожает на дальнейшей разработке и поддержке.


                            1. zelenin
                              08.08.2017 21:25

                              по-моему наличие промежуточного ПО из коробки удешевляет старт, потому что не нужно продумывать например кэширование непосредственно в приложении. По мне так разница небольшая: нджинкс у меня будет кэшировать, или мидлваря перед graphql.


                              1. napa3um
                                08.08.2017 21:32
                                +1

                                Удешевляет старт возможность начать с низкоквалифицированными программистами, не вникая в сложности HTTP/REST. А мидлвари не все принадлежат вашей инфраструктуре. Ну и потом да, нанимать квалифицированных программистов, которые из ваших мидлварей сделают всё то, что уже спроектировано в HTTP.


                                1. vintage
                                  14.08.2017 08:55

                                  Удешевляет старт возможность начать с низкоквалифицированными программистами,

                                  Это миф. Бездумная копипаста слишком быстро начинает затягивать проект в болото.


                                  не вникая в сложности HTTP/REST.

                                  Да какие там сложности?


                                  1. napa3um
                                    14.08.2017 13:41

                                    > Это миф. Бездумная копипаста слишком быстро начинает затягивать проект в болото.

                                    Это не миф, а лишь моё мнение, попытка найти причину существования GraphQL. Сам я тоже предпочитаю чуть больше проектировать, чем плавать в болоте копипаст.

                                    > Да какие там сложности?

                                    Да, сам тоже, конечно, не считаю сложным то, в чём уже имею компетенцию :).


                                1. AndreyRubankov
                                  14.08.2017 09:27

                                  Удешевляет старт возможность начать с низкоквалифицированными программистами, не вникая в сложности HTTP/REST. А мидлвари не все принадлежат вашей инфраструктуре. Ну и потом да, нанимать квалифицированных программистов, которые из ваших мидлварей сделают всё то, что уже спроектировано в HTTP.

                                  Дешевые низклквалифицированные специалисты – это очень дорого.

                                  А найм высококвалифицированных, которые потом перепишут все заново – это еще дороже.

                                  Такое себе удешевление получается =)


                                  1. napa3um
                                    14.08.2017 13:05

                                    Современные стартапы часто работают так: «на карманные деньги» и максимально быстро пишется MVP, минимальный прототип, который хоть как-то шевелится, демонстрируется рабочесть идеи, убеждаются инвесторы, даются денег на разработку, и только тогда нанимается полноценная команда и проект делается с нуля. Удешевление возникает не на одном проекте, а на (условно) сотне, из которых 99 всё равно будут отвергнуты, и только один «выстрелит». См. «посевное финансирование».


            1. galakt
              08.08.2017 21:28
              +1

              Вы уверены, что знаете как работает GraphQL?


        1. QuickJoey
          08.08.2017 15:44
          +1

          По аналогии с SQL, если вы откроете доступ к БД, то злоумышленник может сделать SQL запрос с кучей join которые тупо повесят ваш сервер БД (вам же это не хочется, правда ?).


          именно поэтому удобно использовать хранимые процедуры, к которым доступ открыт, а к таблицам и прямыми запросами к ним закрыт. в процедуре об этом злоумышленнике подумали заранее.


        1. rraderio
          08.08.2017 18:00

          Если GraphQL API не публичный и предназначен для внутренних клиентов (мобильных или веб), можно использовать списки доступа и предварительно одобренные запросы. Клиенты требуют сервер выполнить такие запросы, указывая вместо запроса его идентификатор. Кажется, Facebook применяет такой подход.


          1. begemot_sun
            08.08.2017 19:57
            -1

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


            1. rraderio
              09.08.2017 11:47

              указывая вместо запроса его идентификатор

              Соотвественно эта третья сторона может использовать ваш GraphQL чтобы нагружать сервера, чего никому не хочется.

              Точно так-же как можно нагружать REST или RPC


        1. Hedgar2018
          08.08.2017 21:28

          Необязательно публичным. Пусть злоумышленник сначала авторизуется и станет доброумышленником.
          Сама идея GraphQL довольно странная и действительно непонятно, зачем вся эта гибкость без контроля.
          Я всегда делаю нечто среднее — при необходимости join'a добавляю к ресурсу эндпоинт с суффиксом типа «with_extra_data» (условно) и возвращаю приджоиненные данные. И клиента ограничивает, и 10 запросов не нужно гонять.


          1. napa3um
            08.08.2017 21:38
            +1

            +1, GraphQL кажется полезным, возможно, для работы только с действительно графовыми данными (например, для извлечения френдов выбранной «дальности» из социальной сети). В иных случаях таки кажется полезнее разобраться с «математикой» REST и всеми наработками, уже реализованными в HTTP для него.


          1. zelenin
            08.08.2017 21:53

            Сама идея GraphQL довольно странная и действительно непонятно, зачем вся эта гибкость без контроля

            да почему без контроля-то? контролируйте.


            1. Alexeyco
              08.08.2017 22:01

              Я, все же, советовал бы заранее прикидывать. Да, чуточку сложнее поддерживать действительно полезный Rest-сервис. Чуточку, соглашусь. И писать бэкенд чуть муторнее. Но не менее муторно потом контролировать отступления от заданных рамок. И вот я бы заранее прикидывал, что именно муторнее. Я лично вижу пока, чисто умозрительно, что пока сервис мелкий — да, проще Graphql. Если сервис чисто для интранета — то хрен с ним, да. Лучше. А вот если сервис публичный — то с возрастанием сложности этих данных просто гигантскими темпами начинает расти и сложность все это поддерживать так, чтобы какой-нибудь умник все не поломал к чертовой бабушке.


            1. Hedgar2018
              08.08.2017 23:14

              И всё будет обрастать классами, функциями, ифами для валидации запросов? Интересно даже, как подобный контроль возможен, если GraphQL — библиотека, и наверняка всё очень инкапсулированно.
              Конкретные эндпоинты для конкретных функций интерфейса будут намного чище и поддерживаемее.
              Грубо, одна кнопка на сайте — один эндпоинт. Нет прав для запроса конкретных данных — бросил ошибку.
              GraphQL сразу предлагает дропнуть целый уровень абстракции вместе с системой ролей и не предлагает ничего взамен.


              1. VolCh
                09.08.2017 07:41

                GraphQL — не библиотека, а спецификация. Есть референсная реализация на JavaScript и есть много альтернатив на разных языках, как клиентов, так и серверов.


          1. rraderio
            09.08.2017 13:23

            https://stackoverflow.com/questions/37337466/how-do-you-prevent-nested-attack-on-graphql-apollo-server

            Query whitelisting: This is probably the most involved method, but you could compile a list of allowed queries ahead of time, and check any incoming queries against that list. If your queries are totally static (you don't do any dynamic query generation on the client with something like Relay) this is the most reliable approach. You could use an automated tool to pull query strings out of your apps when they are deployed, so that in development you write whatever queries you want but in production only the ones you want are let through. Another benefit of this approach is that you can skip query validation entirely, since you know that all possible queries are valid already.

            предварительно одобренные запросы


            1. Alexeyco
              09.08.2017 14:54
              +1

              И это убивает гибкость. Нам говорят, что Graphql лучше Rest именно гибкостью. А на деле эта гибкость должна не быть использована.


              1. rraderio
                09.08.2017 16:29

                В проде, да, не нужна, в девелопменте почему нет?


              1. VolCh
                09.08.2017 17:12

                В большинстве случаев такая гибкость не нужна в продакшене, достаточно гибкости при разработке/отладке/тестировании. Все эти хот релоад, дев-окружения и т. п. так и работают — не в прод окружении всё гибко, а на прод статически собирается и фиксируется.


    1. leschenko
      08.08.2017 14:10
      +2

      То, о чем вы пишете есть RPC и существует очень давно. Разве что раньше никак не называли этот подход, а начали называть только с приходом REST и иже с ними.

      Когда вы занимаетесь разработкой как backend, так и frontend, то можете «точить» одно под другое. Но, если у вы пишете только backend, а frontend будут писать совсем другие люди и коммуникации между вами не будет, то вы не можете заранее знать что frontend будет «хотеть».

      Поэтому существует такая штука как REST. Этот подход зачастую избыточен, но независим от сценариев использования.
      А GraphQL по сути попытка убрать из REST избыточность.


      1. begemot_sun
        08.08.2017 14:23
        +1

        Невозможно сделать универсальный интерфейс, т.о. взаимодействие разработчиков всегда необходимо.
        Таким макаром можно SQL в свет выложить :) пусть пользует. А что, очень универсально.


        1. leschenko
          08.08.2017 14:28

          Взаимодействие не всегда возможно.

          Пример: Публичное API.

          Согласитесь, что Facebook, например, скорее всего не будет затачивать свое API для вашего мобильного приложения. Т.е. взаимодействия между разработчиками API и разработчиками frontend'а нет и в данном случае быть не может.


          1. begemot_sun
            08.08.2017 14:42
            -1

            Не соглашусь. Разработчики API facebook понимают какие данные нужны людям, и предоставляют эти данные в удобном для людей виде. Т.о. взаимодействие есть, но косвенное.
            Не бывает сферического API в вакуме. В случае GraphQL это именно этот конь и есть.


            1. leschenko
              08.08.2017 14:48
              +1

              Они не могут знать что надо всем. Потому что кому-то что-то надо, а кому-то нет. Кто-то может сделать дополнительный запрос, а кому-то это «дорого».

              Когда вы сами пишете API, вы можете все «запихать» в 1 запрос. Когда вы используете чужое API, возможно 2 и более запросов. Хуже, когда все выливается в N+1 запросов. А все потому что разработчик API не может знать что вам надо и делать API для вас. У него таких как вы еще 100500 и каждому что-то надо. И в случае с REST такое бывает часто.

              И да, не бывает сферического API в вакуме. О чем я и пишу.


              1. begemot_sun
                08.08.2017 14:59

                Я с вами согласен по части «не могут знать», поэтому они делают как лучше для них.
                Конечно, вы можете сделать 2 запроса и получить 2 результата на что уйдет 2х времени.
                Если вы хозяин API, и видите боль, ну ничего не мешает вам организовать простой интерфейс где возможно сразу выполнить много команд. Проблемы возникнут когда одна команда зависит от другой. Конечно, GraphQL, возможно, решает эту проблему, но опять же я вижу другую проблему — это слишком общий путь получания данных, и эта очень сильная беда как с точки зрения реализации, так и с точки зрения ограничения нагрузки.

                Я как бы не против всяких GraphQL и SQL. Я против того, чтобы это было выложено в паблик без должной работы по ограничению стоимости запросов. И т.о. сам запрос должен содержать в себе информацию о том, какова его сложность выполнения. Есть работы по анализу этого?


            1. acmnu
              08.08.2017 15:13

              Разработчики API Facebook и разработчики GraphQL это одни и теже люди. Более того GraphQL это основной API в Facebook:


              https://developers.facebook.com/docs/graph-api


              1. leschenko
                08.08.2017 16:00
                +1

                У них когда-то был FQL. Но его закрыли.
                Вот как сейчас у Facebook спросить список галерей с количеством фотографий в них? У самой галереи нет счатчика? Запросить сразу все фотографии нельзя. Там еще пейжинг есть.

                С их текущим REST это сделать очень больно.
                Как с помощью GraphQL это сделать? Т.е. не просто ограничить набор полей в выводе, а добавить агрегирующие функции?

                С помощью FQL это было сделать можно. Но, нет больше FQL.


    1. Alesh
      08.08.2017 19:20

      Зачем это всё?

      Ваш вопрос из той же оперы что и например — зачем нам Симфони когда можно отлично закодить на PHP/HTML mixed, не находите?)


      1. begemot_sun
        08.08.2017 20:06

        Нет. Я понимаю ваше стремление улучшить API? которое предоставляется. Но, вы не понимаете моё стремление обезопасить протокол. Когда вы используете принцип простая команда-результат, вы видите всё что происходит на вашей стороне, вы можете собирать статистику о том какая команда сколько стоит. Соответственно, вы можете решать заранее, можно выполнять команду или нет для клиента.
        В случае GraphQL вы не знаете какие конкретно запросы будет слать клиент, это множество значительно больше того множества запросов когда вы используете RPC, соотвественно вы не можете предсказать сложность запроса и время его выполнения, т.к. это множество ОЧЕНЬ большое.

        Вы сделали интерфейс взаимодействия аля SQL и выставили его наружу.


    1. zenkz
      08.08.2017 22:36
      +3

      Поддерживаю вас.
      Почему-то многие разработчики стреляют себе в ногу, когда пытаются использовать технологии не осмысленно, а хайпово.
      К примеру REST — хорош для CRUD приложений. Как только выходишь за рамки манипуляции объектами, то приходится создавать странные маршруты вроде GET /postsAndComments/.
      GraphQL — ради одной точки входа создаём себе кучу проблем вроде непредсказуемого API c потенциальными дырами в безопасности.

      Можете меня не поддерживать, но на текущий момент вижу удобным сочетание REST (для CRUD действий над объектами) и JSON RPC (для всего остального) с добавлением OData по необходимости.


      1. alibertino
        09.08.2017 01:25

        GraphQL — ради одной точки входа создаём себе кучу проблем вроде непредсказуемого API c потенциальными дырами в безопасности

        Никто не мешает в GraphQL реализовать ресурсы в точность так же для CRUD. Откуда берется непредсказуемость и дыры — не ясно, посмотрите примеры, github, например.
        Можете даже root-объекты назвать по привычке GET DELETE PUT POST
        query{
        GET {
        post(id:1){
        title
        }
        }
        }


        1. zenkz
          09.08.2017 21:57

          Мне кажется вы подменяете понятия защищая GraphQL любыми средствами.

          Я не настолько люблю REST, чтобы создавать рут-объекты с именами GET, POST и т.д. Я сторонник принципов KISS и DRY, которые не про GraphQL. Конечно DRY и не совсем про REST тоже…

          Было бы намного практичнее, если бы вы привели пример API, реализованного на GraphQL и документации к нему. А ещё лучше сравнение с аналогичным API на REST.

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


          1. alibertino
            10.08.2017 01:24

            Было бы намного практичнее, если бы вы привели пример API, реализованного на GraphQL и документации к нему.

            Я привел пример https://developer.github.com/v4/, ну и https://developer.github.com/v3/
            Гитхаб шли по абсолютно тому же пути, придумывали способы описать запрашиваемые поля, а когда вышла спека GraphQL просто заюзали его.
            По поводу дыр в безопасности — насколько я понимаю на GraphQL довольно сложно реализовать систему ролей пользователей, т.к. существует почти бесконечное множество возможных запросов.

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

            posts { comments { posts } } }

            Где, posts Array Of Post, а на Post свои права доступа, а на вложенный Post те же самые права доступа и та же самая документация.

            Но опять же, GraphQL абсолютно не заставляет вас быть настолько гибкими, пожалуйста. реализуйте свои явные точки входа, тогда в виде бонуса будет удобный синтаксис и уменьшенный размер пакета из-за выбора полей.


          1. sasha1024
            12.08.2017 01:23

            KISS и DRY, которые не про GraphQL
            В моём понимании, GraphQL — это вполне себе KISS (по крайней мере, он гораздо более KISSный, чем классический REST-style подход).


  1. serf
    08.08.2017 13:53

    когда команда — некий идентификатор команды + список некоторых параметров для этой команды.

    Так делаем сколько нужно ендпоинтов с соответствующей логикой и все, это REST API и есть. Называет ендпоинты командами или чем угодно, а не сущностями и все. Так делают уже десятки лет.


    В случае гибкого GraphQL дело как раз в унификации, как раз в этом цель и есть чтобы выставить ДБ наружу образно говоря, но конечно не напрямую как некоторые могут подумать.


    1. leschenko
      08.08.2017 14:11

      Только это уже будет не REST, а RPC. Хороший (и удобный) REST API написать достаточно тяжело. Очень легко скатиться и начать нарушать его принципы. Иногда оправдываясь такими словами как первоманс.


      1. serf
        08.08.2017 14:12

        Если смотреть на детали, то да, но REST просто получается более частная форма вызова конкретных ендпоинтов.


        1. leschenko
          08.08.2017 14:14

          Все верно.
          RPC — делаю что хочу и как хочу. Уже REST есть какие-то правила.
          А вот воблюдать их или нет — дело выбора каждого.


      1. Alesh
        08.08.2017 19:27

        По большому счету и даже не по большому, REST это тоже RPC)
        GraphQL просто позволяет более развернуто задать параметры этого вызова.


        1. napa3um
          09.08.2017 01:39

          RPC — это когда действие определяется урлом или параметрами запроса, а REST — когда исключительно глаголами HTTP. Хоть эти подходы и выразимы друг через друга, но являются принципиально различными подходами к проектированию.


          1. VolCh
            09.08.2017 07:47

            а REST — когда исключительно глаголами HTTP

            Вы говорите лишь об одном подходе к реализации REST через HTTP, подходе максимально использующем семантику HTTP. Собственно классический HTTP является реализацией REST.


            1. napa3um
              09.08.2017 07:59

              Если хочется абстрагировать REST от HTTP, то пусть будет не «исключительно глаголами HTTP», а «исключительно глаголами из фиксированного списка».


              1. VolCh
                09.08.2017 08:20

                Нет в признаках REST-архитектуры требования фиксированного списка глаголов. Более того, она подразумевает, что список возможных действий над ресурсом становится доступным клиенту только после получения представления ресурса, клиент может даже не знать ничего о действии кроме того, что показать пользователю его название, а потом выполнить запрос, описанный в представлении ресурса.


                1. napa3um
                  09.08.2017 08:21

                  Вы явно перепутали REST с чем-то другим. HATEOAS говорит о связанных ресурсах, а не действиях над ними, действия для всех ресурсов строго одинаковые (не всегда доступные в полном количестве — об этом коды ошибок HTTP). В этой ограниченности глаголов и заключается суть REST.


                  1. VolCh
                    09.08.2017 08:56

                    Это вы явно перепутали REST c HTTP. Откройте хоть вики что ли и посмотрите пример HATEOAS — там явно описаны действия (ваши глаголы), которые можно совершить над ресурсом и никакого отношения к глаголам HTTP они не имеют. Вернее могут иметь, где-то на уровне документации описано, например, что действие


                    <link rel="close" href="https://bank.example.com/accounts/12345/close" />

                    должно осуществляться исключительно методом POST, а может HEAD, а может любым методом.


                    Просто поймите — HTTP и связанные с ним технологии сам по себе может считаться одной из реализацией REST-подобной архитектуры, если строго следовать его семантике. Но никто не запрещает не следовать, а использовать его лишь в качестве траспортного протокола, привязываясь к его семантике лишь в целях минимизации технических проблем, с кэшированием прежде всего.


                    1. napa3um
                      09.08.2017 09:05

                      Вы написали «можно не следовать ресурсной семантике REST, значит, REST позволяет описывать действия, а не только ресурсы». «Можно есть вилкой, а не только ложкой, значит ложки — это вилки». Link rel[ation] описывает ссылку на отношение с другим ресурсом и никак иначе, и действие прикладной области придётся выражать в виде ресурса «операция», а не глагола действия над ресурсом.


                      1. VolCh
                        09.08.2017 12:10

                        Я написал "можно не следовать ресурсной семантике HTTP, но при этом не нарушать принципов REST при использовании HTTP в качестве траспортного протокола".


                        Суть в чём — HTTP по сути протокол прикладного уровня, оперирующий идентификаторами ресурсов в виду URI и фиксированным списком операций над ним в виде методов-глаголов c довольно точной семантикой. В целом точную реализацию спецификации HTTP можно считать REST, если следовать ограничениямия типа запрета на сессии. Но сейчас очень популярно использование HTTP в качестве траспортного протокола, нарушая принципы REST и семантику HTTP на уровне HTTP. Но никто не мешает реализовать принципы REST на прикладном уровне, после разворачивания запроса из HTTP-конверта.


                        1. napa3um
                          09.08.2017 12:15

                          Вы написали «можно не следовать ресурсной семантике HTTP, но при этом не нарушать принципов REST», а я ответил «нельзя». Если вы говорите о том, чтобы реализовать «ресурсную парадигму» не используя в такой парадигме HTTP — то кто ж спорит, конечно, можно и поверх сигнальных костров REST построить. О том и говорю, что GraphQL — это наворачивание ещё одного уровня протокола для того, чтобы можно было воспользоваться готовым фреймворком и докрутить ограничения позже, когда нагрузки действительно возрастут или хакеры заинтересуются вашим сервисом. «Ленивый REST».


                          1. VolCh
                            09.08.2017 12:47

                            Принципы REST можно оставить на прикладном уровне, а на траспортном на них наплевать. GraphQL, SOAP и т. п. — это отказ от использования семантики и прочих прикладных возможностей HTTP (довольно ограниченных и/или неудобных во многих случаях), оставляя его транспортные возможности. Реализовывать на прикладном уровне REST или нет — отдельный вопрос.


                            1. napa3um
                              09.08.2017 12:48

                              Можно и от эзернета отказаться, используя сигнальные костры, я полностью с вами согласен.


                              1. VolCh
                                09.08.2017 13:01

                                Сарказм не уместен. У HTTP по спецификации две отвественности — транспорт и семантика, что даже в его названии отражено. Причём семантика слаборасширяемая и ориентированная на CRUD-операции. Решение выделить семантику на отдельный технический уровень уж точно не аналогично решению заменить езернет на сигнальные костры.


                                1. napa3um
                                  09.08.2017 13:03

                                  Это лишь утрирования для донесения моего мнения. Не понимаю, что ещё вы пытаетесь добиться в этом диалоге.


                                  1. VolCh
                                    09.08.2017 13:21

                                    Донести что HTTP и REST — лишь пересекающиеся области с одной стороны, а с другой, что за не-REST HTTP API может скрываться REST API прикладного уровня, использующей HTTP в качестве траспорта, но почти полностью игнорируя его семантику, например ораничиваясь только GET запросами.


                                    1. napa3um
                                      09.08.2017 13:30

                                      Мне кажется всё сказанное вами очевидным. И кажется, что вы не понимаете акцентов своих собеседников, «проповедуя обращённым».


          1. Alesh
            10.08.2017 12:21

            RPC — это когда remote procedure call. А какая procedure должна быть call, может определяться как глаголами запроса, так и URL. Я имел ввиду в своем посте именно этот аспект.


            1. napa3um
              10.08.2017 12:24

              Глаголами HTTP реализовывать RPC не получится — их ограниченное фиксированное количество. Я имел ввиду в своем посте именно этот аспект.


              1. Alesh
                10.08.2017 12:41
                -1

                Да это понятно, на хабре вообще любимое дело, когда каждый беседует с оппонентом «о своем» :)


  1. DrFdooch
    08.08.2017 14:11

    у GraphQL есть небольшие отличия, которые существенно меняют процесс построения и использования API разработчиками

    не скажу ничего нового, но это небольшое отличие заключается в создании ада на зем бэк-енде.

    и ведь что характерно, очень много новых постов о GQL почему-то вместо акцента на реальных преимуществах и границах применимости, просто позиционируют его как убийцу REST/SOAP/RPC/чегоугодно… аргументируя это «смотрите как можно через один эндпоинт всё сделать!». мыслевирус в чистом виде.

    а то, что статья вроде как бы просто сравнивает подходы, мало меняет её основной посыл.


    1. bevalorous Автор
      08.08.2017 17:12

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


  1. vasIvas
    08.08.2017 14:32

    Разница в том, что rest описывает правила работы над данными.
    А GraphQL описывает ещё и логику, точно также, как и любая другая концепция datastorage.

    Первое, это правило по которому нельзя сувать пальцы в розетку.
    А второе, что нельзя сувать пальцы в розетку — сидя, стоя, стоя на одной ноге, в прыжке, в припляску и т.д.


  1. Electrohedgehog
    08.08.2017 14:52

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

    Может кто-то более понятно объяснить суть технологии? Пока вижу кучу шума и небольшую надстройку на старой рабочей лошадкой.


    1. Alexeyco
      08.08.2017 15:11

      Вы однажды организуете данные и потом фронтенд-разработчик делает что хочет. Без необходимости что-то дорабатывать. К примеру, отдает ресурс данные об авторе. В виде его ID. Это не удобно — требуется делать доп. запросы. Фронтендщик это замечает и обращается к бэкендщику. Это в случае с Rest. В случае с Graphql этого, теоретически, не потребуется. Плюс — Graphql позволяет уточнять, какие из данных нужны. Чтобы лишнего не прилетало. Это в теории. На практике это, конечно, было бы удобно. Но есть и куча минусов.


      1. Electrohedgehog
        08.08.2017 15:38

        А чем именно это отличается от доступа через апи к нормальной БД со всеми необходимыми ключами, связями и т.д.? Вот прямо сейчас работаю над проектом, где легко можно пойти по такому примерно адресу:

        http://192.168.1.175:1337/api/accounts/33/companies

        Получим в виде JSON все компании из таблицы companies связанные по внешнему ключу c записью в таблице accounts с id 33.

        Причём все эти вещи не прописываются руками, апи умеет читать связи в базе данных и единственное что требуется при обновлении её структуры — запустить скрипт конфигурации.


        1. Alexeyco
          08.08.2017 16:44

          Я сам к Graphql отношусь скептически. Не потому, что не люблю все новое. Идея, как мне кажется, просто крутейшая. Но пока технология не очень устоялась. Мое мнение личное, никому не навязываю.

          А касаемо чем отличается. Так ничем не отличается, наверное. За исключением нюансов. Но Graphql — это, по крайней мере, попытка запихнуть хорошую идею в технологию. А не на коленке что-то выдумать. А раз так — можно попробовать дать ей пару лет и посмотреть. Может что и получится хорошее.


        1. quantum
          08.08.2017 19:41
          -2

          А нормальная БД — это какая?


        1. VolCh
          08.08.2017 22:58

          Это и есть по сути такой доступ. С возможность делать Select не *, а указывать список полей, джойнить таблицы.


  1. Alexeyco
    08.08.2017 15:07
    +3

    Я думаю, некоторые из различий говорят в пользу GraphQL. В частности, мне кажется, действительно здорово иметь возможность реализовать свой API как набор небольших функций-распознавателей, а затем отправлять сложные запросы, которые предсказуемым способом извлекают множество ресурсов за один раз.


    А потом кто-то откапывает ваш API и такой:
    {
      authors {
        firstName
        posts {
          title
          author {
            firstName
            posts{
              title
              author {
                firstName
                posts {
                  title
                  [n author]
                    [n post]
                }
              }
            }
          }
        }
      }
    }

    А в ответ ему прилетает целая торба данных. Которая валит сервер. В чистом виде преимущества Graphql перед Rest несомненны. Практика расставляет все точки.


    1. zelenin
      08.08.2017 15:15

      А в ответ ему прилетает

      {"error": "Three levels are allowed maximum."}


      1. Alexeyco
        08.08.2017 16:41
        -2

        Ну а точно прилетает? Есть какие-то фреймы?


        1. zelenin
          08.08.2017 16:44
          +1

          Ну а точно прилетает?

          у вас разве не гипотетический вопрос? как я могу точно ответить? это деталь реализации, к graphql не имеющая отношения.


          1. Alexeyco
            08.08.2017 16:49
            -4

            А, ну тогда не принимается. Принял бы ответ «используем такой-то фрейм, полет нормальный, ничо там не прилетает». А теоретическую возможность ограничить level я даже за решение не приму. Это костыль.


            1. Alesh
              08.08.2017 19:34
              +1

              По моему ответ будет зависить от реализации, а не от того используется GraphQL, REST или что то еще. Если у вас на выдачу коллекции нет лимита, то на больших таблицах результат будет такой же для обычного GET /books.


              1. Alexeyco
                08.08.2017 21:55
                -1

                Вы просто вникните в то, что я написал. Тут лимиты ни при чем. Приведенный выше запрос просто физически сложно эвристически разбивать на джойны. Т.к. там может быть ну вообще все — любая структура данных. Будет выполнено просто гигантское кол-во запросов в цикле. Вопрос не столько о количестве этих данных, сервер начнет дристать еще на стадии агрегации данных. Если не верите — просто попробуйте реализовать у себя какой-нибудь микросервис на Graphql. Желательно, интранет-сервис, чтобы не влететь. И вы увидите, как там оно все реализуется.


                1. Odrin
                  09.08.2017 10:41

                  А что вы будете делать в случае rest и запроса к ресурсу GET /authors x 100500 раз параллельно? Тут запросов в цикле не будет? Теоретическую возможность ограничить кол-во запросов от клиента я даже за решение не приму, это костыль.


        1. asci
          08.08.2017 16:45

          точно так же как и в ресте есть параметр limit и его максимум. Если реализовали — лимит есть, если нет — АПИ дырявое, что рест, что графкл


          1. Alexeyco
            08.08.2017 16:48
            -1

            Ограничивать вложенность — это костыль. Это костылище костыльный.


            1. asci
              08.08.2017 16:50

              Почему?


              1. Alexeyco
                08.08.2017 16:50

                Потому, что это ограничивает не только вредоносные. Но и пользоносные запросы. А если где-то надо будет level 5+? Ну вот надо. А мы бахнули всех под одну гребенку.


                1. zelenin
                  08.08.2017 16:56
                  +2

                  еще раз: реализация ваша. Как хотите так и делайте. На один запрос 5 уровней, на другой 1, на третий — интеллектуально. Это не костыль — это так надо делать.


                  get-запрос на /products (в парадигме rest) должен отдать миллион продуктов или ограниченное на сервере количество? Решать разработчику серверной стороны.


                  1. Alexeyco
                    08.08.2017 16:59
                    +3

                    Вот-вот. Мне сначала тоже «да давай заюзаем Graphql, не надо будет роутинги, ваще ничо не надо будет». А я взял и послушал. Теперь расхлебываю.


                    1. bevalorous Автор
                      08.08.2017 21:43

                      Сочувствую. Лично я обычно перед внедрением технологии X в проект задаю себе два вопроса:

                      1) Есть ли в проекте проблемы, которые после внедрения X исчезнут или существенно уменьшатся?

                      2) Будут ли использоваться те приятные бонусы, которых сейчас нет, но которые появятся после внедрения X?

                      Если ответом на оба вопроса является «нет», я не внедряю X на проект. Эдакое сочетание «не ломай то, что и так работает» и «не плати за бонусы, которые тебе не нужны».

                      Хотя иногда, конечно, желание поэкспериментировать с какой-нибудь новой клевой технологией пересиливает здравый смысл.


                      1. Alexeyco
                        08.08.2017 21:49

                        На самом деле, проблемы настолько были неочевидны. Я не говорю, что они не преодолимы. И я даже теперь часто отстаиваю Graphql. Например, вот звучал вопрос о том, что API теперь позволяет не просто тырить данные справочников сайта, а позволяет интегрироваться с ним. Это, вроде как, плохо. С одной стороны. С другой — вот один раз мне страсть как надо было импортировать справочник товаров с одного сайта. А там постоянно что-то переверстывали. Ну и разве меня это остановило когда?

                        Я всего лишь говорю, что ребята — есть проблемы, которые вот они. Это совершенно конкретные проблемы и обратите на них внимание заранее. И прикиньте для себя — да, в целом писать сервер для Graphql API проще, чем то же но в виде Rest. Но может быть, в вашем случае и черт бы с ним с этим оверхедом.


              1. Alexeyco
                08.08.2017 16:55

                Не помню, где-то общался со специалистом, который от меня не знал, куда деться. Он тоже о Graphql рассказывал. И он предлагал знаете, как. Вот мы начали выполнять Graphql-запрос. И заранее определяемся, скажем — мы готовы выполнять запросы в среднем за 0,1с и затрачивать на это столько-то ресурсов. Начинаем выполнять запрос — начинаем считать. Если ресурсов или времени тратится больше, чем надо — отрубаем запрос.

                Это примерно из той же оперы. Низкая кучность стрельбы компенсируется увеличением диаметра снаряда.


      1. Alexeyco
        08.08.2017 16:48
        +3

        И кстати, для приведенного мной варианта трех уровней было бы вполне достаточно, чтобы серверу ощутимо дать под дых. Такими запросами ддосить кого-то — одно удовольствие.

        И потом — если три уровня максимальны, то вообще-то их может и не хватить. Что тогда? Придется делать какие-то запросы разрешенными, какие-то запретными. Еще раз повторяю — Graphql очень крут. Флаг в руки. Но как только возникает что-то подобное, сразу становится понятно, что принцесса-то… небритый мужик.


        1. zelenin
          08.08.2017 16:51

          И кстати, для приведенного мной варианта трех уровней было бы вполне достаточно, чтобы серверу ощутимо дать под дых.

          вы, как разработчик вашего api, знаете сколько уровней достаточно. Столько и сделайте. Сотый раз: graphql не описывает серверную реализацию.


          Но как только возникает что-то подобное, сразу становится понятно, что принцесса-то… небритый мужик.

          вы просто не понимаете, что эта спецификация о языке запросов


          1. Alexeyco
            08.08.2017 16:58
            +1

            Я ни слова претензии в адрес теоретической составляющей и не высказал. Внимательнее надо читать — я описываю нюансы реализации и говорю, что не все так безоблачно. А вот почему от вас бурная реакция — вопрос. Я ничего не наврал, никого не оскорбил.


            1. zelenin
              08.08.2017 17:04

              я внимательно читаю:


              Еще раз повторяю — Graphql очень крут. Флаг в руки. Но как только возникает что-то подобное, сразу становится понятно, что принцесса-то… небритый мужик.

              если принцесса — разработчик, то вы правы. Ведь к GraphQL эти претензии не относятся. Но в комментах к каждой статье про GraphQL одно и то же — а именно непонимание что собственно это такое.


              А вот почему от вас бурная реакция — вопрос

              если будете внимательнее читать, то не будете переносить свое настроение на оценку моей реакции.


          1. Alexeyco
            08.08.2017 17:06
            +2

            Тогда я прямо сейчас вам готов родить отличнейшую концепцию. Там вообще ничего не потребуется.

            Короче. Надо постировать на сервак прямо SQL-запросы. А уже на сервере разгребать, что из этого вредоносное, а что нет. Но это уже ваша проблема. Как технология? Я считаю, крутяк! )))


            1. begemot_sun
              08.08.2017 20:28
              +2

              Привет брат, я с тобой :)


              1. Alexeyco
                08.08.2017 21:31

                Спасибо ))) а то я уже подумывал утопить горе в вине )))


    1. bevalorous Автор
      08.08.2017 16:56
      +4

      А в случае REST API можно забыть добавить аутентификацию и авторизацию для конечной точки, и злоумышленник получит данные, к которым он по идее не должен иметь доступа.

      Или другой сценарий: конечная точка, возвращающая список данных, разбитых на страницы, не проверяет входные параметры, присылаемые клиентом. В результате можно запросить весь список целиком или просто очень много элементов на одной странице, и сервер свалится из-за огромного объема запрошенных данных.

      GraphQL — всего лишь концепция построения интерфейса доступа, которая ослабляет связанность клиента и сервера. На мой взгляд, проблема, которую вы описываете, вообще не имеет отношения к тому, на чем у вас реализован API. Это скорее вопросы информационной безопасности.


      1. Alexeyco
        08.08.2017 17:03

        То есть, защита от дурака — проблема дурака?


        1. zelenin
          08.08.2017 17:09

          написано ровно наоборот: если парадигмально по GET /products мы получаем список продуктов, то не надо забывать о здравом смысле (читай, лимите).


          1. Alexeyco
            08.08.2017 17:16
            -2

            Это никак не связанные вещи. То, что при реализации Graphql принято делать костыли и это норма я уже понял. Теперь я пытаюсь выведать нюансы.

            Сравнивать уровень вложенности Graphql запроса и количество отдаваемых пагинатором сущностей — это ерунда полная. Это совершенно разные лимиты и влияют они на работу сервера по-разному.

            Для меня абсолютно не аргумент, что тут у нас теория, а тут у нас практика. Теория и практика обслуживают друг друга и разделять их совсем было бы глупо. Если у авторов этого чудесного стандарта не нашлось идей, как этот Graphql столь же красиво реализовать, это говорит о многом.


            1. zelenin
              08.08.2017 17:21

              у авторов этого чудесного стандарта не нашлось идей, как этот Graphql столь же красиво реализовать, это говорит о многом.

              и еще раз: спецификация рассказывает о том как общаются клиент и сервер, а не как сервер обрабатывает запросы.


              Вот ниже давали ссылки на json-api. Вы спеку читали? там есть вообще что-то про серверную реализацию? Почему в случае с graphql должна быть другая ситуация?


              1. DrFdooch
                08.08.2017 18:07
                +1

                json-api просто не называют серебряной пулей и убийцей REST :)


    1. arvitaly
      08.08.2017 18:31

      Если вы про вложенность, решается элементарно кешированием, все реализации GraphQL это делают в первую очередь, если про объем, то и в REST без лимитов все будет плохо.


  1. Marwin
    08.08.2017 15:18
    +8

    подобных статей сотни… да все уже поняли, что есть "спецификация" GraphQL, и что это типо мегакруто и всё такое.
    Но напишите хоть одну статью о его реальном применении в реальной жизни в полностью реализованном проекте, где есть и авторизация и роли и ограничения, подходы к кэшированию и прочий обвес. В REST это всё решается на раз, есть куча примеров и наработок. В графе лучших практик — ноль целый ноль десятых.


    1. zelenin
      08.08.2017 15:27
      -1

      действительно, было бы интересно, но собственно чего тут обсуждать? все будет то же самое, что и в rest — мидлвари на сервере для авторизации, кэширования, подсчета уровней вложенности, рейт лимитинга. То есть специфика только одна — проверка на рекурсию и многоуровневость запросов.


      1. Marwin
        08.08.2017 17:26
        +4

        я, видимо, еще не дорос до проектов с несколькими уровнями вложенности/разделения функционала ))
        Я делаю апи в виде тупо методов, в каждом из которых проверяем ключ токена на роль/права, смотрим в редис есть ли кэшированная версия ответа, если нет, делаем селект, сериализуем, отдаем json клиенту. Пытаясь придумать, как это перенести на идеологию GraphQL сразу возникает куча практических вопросов:
        1) как УДОБНО понимать к какой таблице и столбцам имеет доступ токен без миллиона if блоков
        2) как прикрутить редис к этой истории, если запросы динамические по столбцам. Опять миллион if на проверку есть ли закешированный запрос именно с этим набором?
        3) как планировать индексы в БД
        4) как делать пост-обработку данных, когда клиент должен видеть не сырое содержимое столбца, а какой-то человеческий вид. Опять миллион if на тему а содержится ли этот столбец в запросе?
        Я к тому, что хорошо бы увидеть вообще другой взгляд на решение вышеописанных проблем/сценариев в реальном коде, как это лучше делать, чтобы не изобретать велосипеды в поисках оптимальности.


        1. zelenin
          08.08.2017 17:33
          -1

          Я делаю апи в виде тупо методов, в которым проверяем ключ токена на роль/права, смотрим в редис есть ли кэшированная версия ответа, если нет, делаем селект, сериализуем, отдаем json клиенту.

          если в rest у вас несколько endpoint'ов, то в graphql у вас несколько resolver'ов. Просто они не снаружи, а внутри, и чуть по другому работают, но суть та же.


          на все вопросы ответ один: делайте как делали. graphql к этому никак не относится.



    1. Alesh
      08.08.2017 19:40

      В графе лучших практик — ноль целый ноль десятых

      Ну вообще-то зря вы так) Facebook использует GraphQL(like) в своем GraphAPI (Странное совпадение префиксов, да?) и вполне успешно.


      1. Marwin
        08.08.2017 20:04

        ну так я рад за них, но разве они рассказывают, что именно там у них под капотом творится и сколько уровней абстракций надо добавить между этим GraphQL и БД, которые бы решали сопутствующие проблемы


      1. sentyaev
        09.08.2017 04:25

        Про Facebook все понятно. Я много читал про GraphQL, выглядит прикольно.
        У меня всего один вопрос, на который я не могу найти ответ: что GraphQL улучшает? Напремр — может ли он сократить время разработки, может ли он сделать поддержку дешевле, можно ли нанять разработчиков с более низкой квалификацией (имею ввиду что начинающие разработчики могут быть более продуктивны используя GraphQL, а не REST).
        Я понимаю что все вопросы про деньги, ну так мы же помогаем бизнесу быть более эффективным.


        1. VolCh
          09.08.2017 08:07

          Навскидку, по сравнению с классическими HTTP-запросами, улучшает:


          • уменьшает объём передаваемых данных в ответе — клиент определяет, что ему нужно с точностью до поля
          • решает проблему множественных запросов типа 1+N — клиент определяет, что ему нужно не в плоской структуре, а в графе объектов. Грубо, указывает, нужно ли ему здесь и сейчас "джойнить" вложенные данные
          • "из коробки" что-то вроде статической типизации, что по утверждениям многих упрощает поддержку
          • увеличивает независимость фронтенд и бэкенд разработчиков. Фронтендеры больше не нуждаются в заказывании "заказывать" бэкендерам новые ендпоинты (или параметризацию имеющихся) для задач типа "тут нам нужно получить только список айдишников постов, тут то же самое, но с названиями и авторами, а тут полностью развернуть дерево комментариев". Бэкендеры один раз описывают то, что у них есть, а фронтендеры комбинируют это как им угодно в своих запросах.


          1. sentyaev
            09.08.2017 09:50

            уменьшает объём передаваемых данных в ответе — клиент определяет, что ему нужно с точностью до поля

            Это самый слабый аргумент в пользу GraphQL. В любом нормальном API по дефолту включен пэйджинг, соответственно врятли за раз передается больше 100 (ну пусть 200) объектов. Соответственно самой долгой операцией будет время на установку соединения, а не на передачу данных. Т.е. этот агрумент имеет смысл когда вы начинаете экономить на спичках, т.е. объем передаваемых данных влияет на стоимость, причем существенно. Проще говоря — это преждевременная оптимизация.

            решает проблему множественных запросов типа 1+N — клиент определяет, что ему нужно не в плоской структуре, а в графе объектов. Грубо, указывает, нужно ли ему здесь и сейчас «джойнить» вложенные данные

            Опять же — преждевременная оптимизация. С другой стороны, возможно, непродуманный дизайн API. Ну а если развивать тему, то если задизайнили неправильно, то в GraphQL будет тоже самое, т.е. потребуется рефакторинг и, возможно, изменение интерфейса/структуры.

            «из коробки» что-то вроде статической типизации, что по утверждениям многих упрощает поддержку

            Как я понимаю это добавит intellisense? Это выглядит довольно полезным, но не киллер фичей.

            увеличивает независимость фронтенд и бэкенд разработчиков. Фронтендеры больше не нуждаются в заказывании «заказывать» бэкендерам новые ендпоинты (или параметризацию имеющихся) для задач типа «тут нам нужно получить только список айдишников постов, тут то же самое, но с названиями и авторами, а тут полностью развернуть дерево комментариев».

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

            Бэкендеры один раз описывают то, что у них есть, а фронтендеры комбинируют это как им угодно в своих запросах.

            Давайте спустимся с небес на землю. Вы хоть раз видели проект где можно вот так сразу «один раз описать» и потом не переделывать? То требование новое появится, то выяснится, что в существующем требование что-то не учли.

            Всем этим я не пытаюсь сказать, что REST хороший, а GraphQL плохой.
            Я лишь пытыюсь понять где же его киллерфича, что вот прям нужно переходить.

            Вот с подходом REST я знаю одну киллерфичу — ничего не нужно чтобы работать с API, т.е. из браузера или curl просто делаете GET/POST и все. Все, все умеют с этим работать. Для каждого языка есть фреймворк, в некоторые уже все в стандартной библиотеке есть чтобы сделать простой сервер, и опятьже все, все знают как это готовить. А главное оно работает, и работает хорошо.


            1. VolCh
              09.08.2017 12:36

              Это самый слабый аргумент в пользу GraphQL. В любом нормальном API по дефолту включен пэйджинг, соответственно врятли за раз передается больше 100 (ну пусть 200) объектов.

              Речь, прежде всего, о форме объектов. Грубо, общепринятый REST отдаёт все скалярные поля объектов, да ещё может разворачивать связанные ресурсы и списки без возможности контролировать это с фронтенда.


              Опять же — преждевременная оптимизация.

              Это не оптимизация, а упрощение клиентской части (пускай и за счёт усложнения серверной). Цепочки запросов сложнее реализовывать, чем один запрос.


              С другой стороны, возможно, непродуманный дизайн API.

              Ну вот нужно нам на фронтенде показывать то только названия статей, то кроме названий и какие-то связанные объекты, например авторов (авторы — отдельная сущность). По сути у нас три варианта:


              • делаем ендпоинт получения плоского списка статей, в одном из полей которого идентификатор автора, плюс второй ендпоинт получения автора по идентификатору. Классическое 1+N. Ну можно сделать второй ендпоинт по типу batch, по списку идентификаторов
              • делаем один ендпоинт получения списка статей сразу с развернутыми авторами, передавая их даже если сейчас они фронтенду не нужны
              • делаем два ендпоинта — один с плоским списком, другой с развернутым, фронтенд дергает тот который больше подходит.

              Как я понимаю это добавит intellisense? Это выглядит довольно полезным, но не киллер фичей.

              В том числе, но основное, имхо, проверка корректности запроса до его фактической отправки. В идеале в компайл-тайме.


              Команды должны сотрудничать, а не изолироваться.

              Речь не про изоляцию, а про уменьшение зависимостей, про увеличение возможностей работать параллельно.


              Давайте спустимся с небес на землю. Вы хоть раз видели проект где можно вот так сразу «один раз описать» и потом не переделывать?

              Нет, конечно. Но число запросов на переделку (вернее доделку) снижается, когда фронтендеры сами получают возможность формировать запросы на каком-то языке. В рамках имеющейся можели конечно — речь не о создании новіх сущностей, полей, связей, а о показе имеющихся через API. Простой пример: наученный горьким опытом я почти на автомате добавляю в корни агрегатов время создания и модификаци. При согласовании классического API с фронтендерами они об этих таймстампах не вспомнили, или отказались, чтобы уменьшить трафик, соотвественно эти поля остаются только для "служебного пользования". Потом внезапно они им требуются и не хоть пару строк да надо дописать. С GraphQL я бы их сразу включил в тип, сначала бы их не выбирали (благо аналога SELECT * нет), а потом стали бі вібирать, меня не дергая.


            1. VolCh
              09.08.2017 12:44

              P.S,


              Всем этим я не пытаюсь сказать, что REST хороший, а GraphQL плохой.

              Я тоже не пытаюсь. Как де-факто фуллстэк-разработчик, я в восторге от GraphQL на фронтенде, и испытываю сдержанный оптимизм от него на бэкенде в среднесрочной перспективе. По факту сейчас комбинирую оба подхода: сервисы (в основном на PHP) работают по RESTish, клиент по GraphQL, а а между ними шлюз.


              1. sentyaev
                09.08.2017 14:43

                Речь, прежде всего, о форме объектов. Грубо, общепринятый REST отдаёт все скалярные поля объектов, да ещё может разворачивать связанные ресурсы и списки без возможности контролировать это с фронтенда.

                Да понятно что можно, только зачем? Лично у меня еще небыло проблемы что передается шлишком много данных, обыно проблема что данных недостаточно и нужно еще пару полей добавить.

                Это не оптимизация, а упрощение клиентской части (пускай и за счёт усложнения серверной). Цепочки запросов сложнее реализовывать, чем один запрос.

                Пойду хелловорд какой-нить напишу, а то этот момент меня смущает.

                Ну вот нужно нам на фронтенде показывать то только названия статей, но кроме названий и какие-то связанные объекты, например авторов (авторы — отдельная сущность).

                Кстати хороший пример. У меня есть подобные сущьности в проекте. В монге есть коллекция Статьи и коллекция Авторы. Делаем просто, в Статью добавляем список Авторов, но не полный объект, а некий минимальный сабсет (id, имя например). Конечно считаем что мы предметную область знаем. Ну и все, /articles вернет статьи с минимальной информацией об авторе. Ну и да, такой момент, у меня в проекте монга как раз используется чтобы «готовить» данные для клиентских приложений (на самом деле даже сложнее ибо проекту уже много лет).

                В том числе, но основное, имхо, проверка корректности запроса до его фактической отправки. В идеале в компайл-тайме.

                Я не уверен как это можно будет делать, т.к. вы используете такие фразы как «как говорят», «в идеале». Т.е. либо вы не пробовали, то ли этого еще нет. Предлагаю тогда это не обсуждать просто.

                Речь не про изоляцию, а про уменьшение зависимостей, про увеличение возможностей работать параллельно.

                Для того чтобы работать параллельно, неважно какую технологию вы используете, прежде всего фронт и бэк команды должны договориться об интерфейсе. Другими словами если это REST, то должен быть список ресурсов и модели, если GraphQL то схема и список запросов. Т.е. одно и тоже.

                Нет, конечно. Но число запросов на переделку (вернее доделку) снижается, когда фронтендеры сами получают возможность формировать запросы на каком-то языке.

                Не очень понимаю, все равно же на бэкэнде эти новые запросы нужно прописать.

                С GraphQL я бы их сразу включил в тип, сначала бы их не выбирали (благо аналога SELECT * нет), а потом стали бі вібирать, меня не дергая.

                Тут нужно каждый случай нужно рассматривать отдельно. У меня продход простой, в начале проекта отдаем данные по максимому, далее мониторим, профайлим, и если действительно нужно, то оптимизируем.
                Тут я как раз не знаю зачем вы экономили на трафике, это только вы знаете.
                Но опять же, даже если бы вы включили эти поля в GraphQL схему, а на самом деле их не отдавали, вас же фронтендеры всеравно же попросили их включить, так? Да и javascript язык динамический, вы добавили поле в модель и все, можно пользоваться. Я к тому, что на фронте работы в этом случае одинаковое количество, на бэкэнде тоже. Профит где?


          1. Alexeyco
            09.08.2017 16:08

            По сравнению с чем именно?


  1. altexxx
    08.08.2017 16:20
    +2

    Что-то не могу понять, зачем GraphQL сравнивать с REST; было бы логичнее выбрать похожий по смыслу формат, например json-api

    http://jsonapi.org/format/#fetching-sparse-fieldsets (можно указывать, какие поля возвращать)
    http://jsonapi.org/format/#fetching-includes (можно указывать связанные ресурсы, и т.д.)


    1. Alexeyco
      08.08.2017 17:08
      -4

      Потому, что jsonapi создал кто? А Graphql создали в Фейсбуке. Все, что делают в Фейсбуке — круто. React сделали в Фейсбуке? Вот это круто. Секта свидетелей Дениски Абрамова как она есть ))


      1. artembloom
        09.08.2017 15:38

        Он Даниил:)


  1. Sartor
    08.08.2017 17:43

    Очень плохо, что GraphQL позиционирует себя как «забейте что там будет думать разработчик на бекенде — сделайте у себя идеальные запросы под любой случай жизни».

    Так не бывает. Если фронтендщик вообще не задумывается хоть немного над сложностью генерации стуктуры на бекенде, которую он хочет получить в своём запросе — это просто плохой разработчик.

    Не бывает в мире сразу и быстрых, и универсальных, и безопасных решений.


    1. alibertino
      08.08.2017 18:49

      GraphQL себя так не позиционирует, откройте документацию http://graphql.org/:

      Ask for what you need, get exactly that

      Точность получаемых данных, т.е. выбор только нужных полей, с точностью до одного.
      Get many resources in a single request

      Представление сложной выборки с помощью одного запроса, с добавлением batch можно получить реально ВСЕ, что нужно одним запросом.
      Describe what’s possible with a type system

      Строгая типизация запроса, фишка именно в том, что типы включены в спецификацию!

      Все сказки про backend — лишь сказки, GraphQL не решает проблем на сервере, но и не создает их, попробуйте и увидите, что ничего не меняется в этом плане. А вот клиент-серверное взаимодействие становится на порядок удобнее. Ну, пока инструменты еще не все готовы, но даже уже с тем, что есть. А уж возможностей понаписать удобств из-за типизации и глубокой интроспекции — сколько угодно, вопрос времени.


      1. VolCh
        08.08.2017 23:07

        Как минимум graphql создаёт на сервере проблему «джойна» заранее неизвестных сочетаний «таблиц».


        1. alibertino
          09.08.2017 01:07

          На самом деле, нет. Фильтрация, группировка и сортировка обычно происходит на верхнем уровне запроса, остальные джойны — по уже выбранным айди. А здесь уже проблем не так много, во-первых, даже дополнительные запросы будут очень легковесны, во-вторых, чаще всего бэкенд, это не просто выборка из реляционной БД и многие вещи лежат в кэше. Это из простых вариантов. А вообще, есть и поинтереснее решение, хотя оно применяются и в любой другой парадигме — это динамический бэкенд, это статистика запросов, на основе которой, определенные джойны выполняются заранее для определенных моделей.
          Да и тема слишком узка, для малых проектов, все это не важно, для крупных, там все равно кэширующие решения будут сложнее, чем джойны.

          Дальше, никто не мешает, в конце концов, обрабатывать на сервере запрос, как единый и знать, какие джойны понадобятся, текущие популярные реализации в виде иерархических подзапросов — всего лишь один из вариантов. Можно маппить весь запрос на SQL, можно хотя бы вычислять джойны, что угодно.
          Потому, что GraphQL не про сервер, а про декларативное представление куска данных, но с описанными типами.


          1. VolCh
            09.08.2017 08:39

            Я не про количество или тяжесть запросов, а про необходимость разработки какого-то механизма маппинга декларативных описаний запросов в императивные команды типа SQL. В случае REST-подобных интерфейсов, такой маппинг простой в общем случае: один ендпоинт — один захардкоженный запрос, возможные "таблицы" известны на этапе проектирования ендпоинта, изменяются только параметры типа идентификаторов. Грубо — один ендпоинт для получения плоского списка постов, второй — для получения его же, но с деревом комментариев.


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


            1. alibertino
              09.08.2017 09:37

              Откуда берется идея, что фронтенд что-то диктует? GraphQL абсолютно не об этом, это всего лишь формат передачи данных, все остальное, и вложенность, и сложность, и известность всех таблиц — решается индивидуально! Не выдумывайте проблемы там, где их нет.
              Еще раз, нет никаких проблем в анализе запроса, смотрим, требуется ли клиенту поле «дерево комментариев» и если да, джойним что надо (в вашем случае, запрашиваем второй endpoint, вместо первого). Рассматривайте GraphQL, как возможность не плодя сущности в языке запроса делать то же самое. Т.е. вместо множества endpoint'ов posts и postsWithComments и postsWithAuthors есть
              posts и posts { comments } и posts{ authors }.
              И маппинг нужен только в случае, если у вас уже есть написанный сервер с готовыми обработчиками запросов для REST. Если пишете сервер для GraphQL с нуля — все эти вопросы уже заложены в архитектуру, вплоть до выбора БД. Уже есть и готовые облачные решения, правда не от крупных вендоров, ждем и их. Parse с поддержкой GraphQL — было бы вообще идеально.


              1. napa3um
                09.08.2017 09:44

                Справедливости ради, в REST для вашего примера тоже можно обойтись одним эндпоинтом с выбором полей или набора полей через query-параметр.


                1. alibertino
                  09.08.2017 09:52

                  Т.е. изобрести свой GraphQL, без спецификации, готовых решений и т.д. Можно, наверное, все это делали.


                  1. napa3um
                    09.08.2017 10:22
                    +1

                    Это у HTTP нет спецификаций?! Я придерживаюсь противоположного мнения — это GraphQL приводит к переизобретению REST, позволяя откладывать проектирование ограничений эндпоинтов «на потом». Для тех, кто не осилил REST/HTTP (ресурсная семантика имеет некоторый порог вхождения, примерно как между процедурным и ООП подходами, а спецификация слишком сложна — всё эти коды ошибок, непонятные заголовки, понятия идемпотентности и прочая ересь) и продолжает пилить API в RPC-стиле («Мне нужно просто выполнить действие на сервере! Зачем мне отдельный ресурс?»)


                    1. alibertino
                      09.08.2017 11:46

                      Боже, причем тут HTTP? Как он поможет вам выбрать поля?

                      GraphQL приводит к переизобретению REST, позволяя откладывать проектирование ограничений эндпоинтов «на потом».

                      «На потом» — это в вашей голове.
                      Для тех, кто не осилил REST/HTTP

                      Боже…
                      всё эти коды ошибок, непонятные заголовки, понятия идемпотентности и прочая ересь

                      Ну прям очень сложно, бедные facebook-архитекторы… А идемпотетность вообще только в мечтах и демагогических высказываниях, когда по сути сказать нечего.
                      «Мне нужно просто выполнить действие на сервере! Зачем мне отдельный ресурс?»

                      Ну да, давайте спор функциональщина/ООП головного мозга ввернем, чо уж там. И да, не хочу я все называть существительными, назовите это «ниасилил» или порогом вхождения, обычно, это называют здравым смыслом. Это в REST пытаются делать все ресурсами, просто подогнать под удобный, элементарный формат, никакого отношения к реальному миру и языку это не имеет, просто 90% случаев выгоднее, чем 10%.
                      Вашу точку зрения я понял, вместо аргументов по теме, оскорбления в адрес собеседника, удачи.


                      1. napa3um
                        09.08.2017 11:50

                        Не знаю, что мне делать с вашими молитвами. Вроде, я не отнимаю у вас GraphQL, не нужно так сильно переживать.


                        1. alibertino
                          09.08.2017 11:54

                          Хабр читают 10 млн человек, демагогию и троллинг нужно изобличать в явном виде.


                    1. VolCh
                      09.08.2017 13:18
                      +1

                      Это у HTTP нет спецификаций?!

                      У HTTP есть. Но они оперируют понятием ресурса и его представления, не документируя управление его представлением. Максимум можно выбирать одно из доступных представлений. Грубо, HTTP специфицирует как получить JSON представления ресурса, но не позволяет регулировать какие поля включать в JSON, а какие нет.


                      1. napa3um
                        09.08.2017 13:36

                        Сомнительная сложность в том, чтобы запрограммировать обработку query-параметра для конфигурирования полноты содержимого возвращаемого ресурса, но если вам обязательно нужны стандарты для этого (например, для автогенерации каких-то частей бэка/фронта), то привлекательнее в этом смысле выглядит ODATA, как раз потому, что не идёт против течения, используя все возможности HTTP, а не оборачивая это всё в протокол ещё одного уровня.


              1. VolCh
                09.08.2017 12:55

                GraphQL абсолютно не об этом, это всего лишь формат передачи данных

                Не согласен. Это формат запросов, прежде всего, в котором обязательноц частью является и спецификация формата ответа.


                Если пишете сервер для GraphQL с нуля — все эти вопросы уже заложены в архитектуру, вплоть до выбора БД.

                Пробовал. В экосистеме PHP поддержка GraphQL, особенно вкупе с SQL-базой оставляет желает лучшего. Подход "по единственному требующемуся API выбираем платформу влоть до СУБД" может и имеет право на жизнь в каких-то проектах, но на моей практике различных интерфейсов к одним и тем же данным/операциям множество, а тип СУБД или вообще её наличие определяется совсем по другим критериям чем простота/сложность прикручивания к ней конкретного API.


  1. AmdY
    08.08.2017 19:48
    +3

    Уже не раз сталкивался с этой проблемой, разработчики не знают что такое REST и из-за этого делают уродливые апи с кучей лишних вызовов.
    REST — это архитектура предпологающая клиент-серверное взаимодействие, БЕЗ хранения промежуточного состояния. Нет состояния, нет проблем, есть куча фишек вроде кеширования и слоистости. Это не про ресурсы /user:id user/:id/comment/:id, не про вербальность GET-PUT-DELETE… как думают многие и откуда растёт миф:
    Пользоваться старой REST-моделью это как заказывать пиццу, затем заказывать доставку продуктов, а затем звонить в химчистку, чтобы забрать одежду. Три магазина – три телефонных звонка.

    REST не запрещает тебе сделать метод POST /doMagic {pizza: {}, address: {}, tea: {}}, и если ты пошлёшь все необходимые данные, то он закажет пиццу, доставку и включит чайник. Отличие от классического подхода то, что ты не установил адрес доставки при регистрации пользователя, а при запросе взял его сс сервера, а отправляешь его явно на /doMagic в виде сырых данных либо идентификатора по которых его можно получить из стораджа (вреде userId).

    Это к тому, что GraphQL тоже является REST подходом, просто у него апи не VERB resource/:id и вам никто не мешает делать такое апи. Например мы, посылаем декораторы, чтобы сказать какие поля получить
    GET /user/:id?decorators=name,address,comments.count.
    Не придумывайте себе исскуственных ограничений, которые не описаны в настоящем REST.


    1. alibertino
      09.08.2017 01:14

      Все верно, GraphQL — логичное развитие не только REST, но и многих других (и OData и RPC). Здесь есть один нюанс, что промежуточного состояния как бы нет, но за счет графовой структуры мы можем состояние как бы «засунуть» на вершину, а потом по ребрам передать. А сейчас то же самое с последовательными запросами (batch) в рамках одного.
      Главное отличие — велосипед написан, он вполне адекватен, выполняет все, что декларирует, зафиксирован, есть поддержка крупного вендора. Ну и удобный синтаксис, наверное, главное.


    1. VolCh
      09.08.2017 09:04

      Всё же отстутствие промежуточного состояния лишь один из признаков REST. Другие важные в контексте поста и обсуждений — он оперирует идентифицируемыми ресурсами через их представления и гиперссылки.
      GraphQL же в общем случае оперирует графами объектов.


  1. KirEv
    08.08.2017 21:31
    +1

    Давно смотрю в сторону GraphQL, в REST бывает в напряг плодить эндпоинты, особенно в большом проекте, от документации которых бедный свагер распухает невероятно…

    Но меня коробит от запросов вида

    /graphql?query={ book(id: «1») { title, author { firstName } } }


    А кто переживает по поводу избыточности количества запросов в REST: «отправь 10 запросов чтобы получить полную информацию для ItemID» — обычно добавляю еще 1 ендпоинт и композитор (ну я так называю, поправьте), композитор на ендпоинте в свою очередь визывает нужные методы и собирает данные, выдавая все 1 респонсом.

    Все четко, понятно кто (ендпоинт) за что отвечает, никакой магии.


  1. AndreyRubankov
    09.08.2017 10:01
    +2

    GraphQL невероятно вкусно выглядит со стороны фронтенда, когда тебе нужно вытащить конкретные поля и это можно сделать за 1 запрос к серверу!
    Facebook API – отличный пример работы GraphQL.

    Но лично для меня так и не понятно, как же это все будет работать на стороне сервера.
    В статье приведены два примера уровня Hello World, где все элементарно просто и красиво.

    Но как это будет в случае, когда запрос должен будет выгребать данные из Реляционной СУБД (Postgres)?
    К примеру все тот же элементарный пример: Books + Author + Comments.

    В моем представлении, для реализации этого подхода на стороне сервера начинается полная вакханалия. Нужно отдать информации про автора из одной таблицы, про книгу из другой, а про комменты из третьей.

    А это значит, что нужно сделать 3 запроса к СУБД для того. Или это нормально?

    Если попробовать оптимизировать и сразу доставать все, то можем нарваться на ситуацию, что фронтенд не запрашивал этих данных, а значит на базу будет идти лишняя нагрузка.


    1. rumatavz
      09.08.2017 10:19

      Не знаю как для GraphQL, но для OData в мире дотнета за все это отвечает ORM. Кода на сервере писать вообще не нужно.


      1. AndreyRubankov
        09.08.2017 10:42

        На сколько я помню, OData имеет имплементацию только в .NET мире, или я ошибаюсь?

        + А как работать в ситуации, когда у тебя часть данных должны придти с внешнего сервиса? к примеру: геолокация или какие-то инвентори/прайсы т.д.


        1. rumatavz
          09.08.2017 21:17

          Я получаю от ORM IQuerible и скорее всего могу сделав проекцию добавить туда еще что то не сломав при этом тот же пейджинг. Но не поручусь, нужно пробовать.


    1. zelenin
      09.08.2017 11:27

      А это значит, что нужно сделать 3 запроса к СУБД для того. Или это нормально?

      как хотите. Хотите 3 запроса, хотите 1 с джойнами, хотите orm воспользуйтесь. Собственно запросы пишете вы.


      1. AndreyRubankov
        09.08.2017 11:58
        +1

        Отличный ответ из разряда: «Проблема на вашей стороне» ;-)

        Конкретная проблема:
        Есть Книги, есть Автора, есть Комментарии к книгам, все это в разных таблицах.
        Через GraphQL делается 2 запроса на книгу с bookId:
        1. запрос на книгу + автора книги
        2. запрос на книгу + автора + комменты

        Я вижу 3 варианта реализации на бекенде:
        1. делать маппинг «в лоб» (как показано в статье), это будет 2 запроса к базе в первом случае и 3 во втором.

        2. делать «оптимизацию», то получим 1 большой запрос и в маппинге просто результаты будем разгребать.
        но в этом случае будет сложный запрос как в случае с комментами, так и без них. Это тоже плохо.

        3. делать «по-умному», но это будет очень сложная логика по созданию запроса к базе, грубо говоря, нужно будет сделать конвертор «GraphQL to SQL» для конкретного проекта и любое небольшое изменение будет требовать большого объема работ.

        Я не силен в GraphQL особенно со стороны бекенда, потому мне интересно: как это должно быть? Какой подход правильный?
        Из всех статей про GraphQL я видел только радостные отзывы, как это удобно для фронтенда и ни разу не видел примеров как это выглядит со стороны бекенда.

        Вы можете подсказать, как это должно быть на стороне бекенда? У вас есть с этим опыт?


        1. alibertino
          09.08.2017 12:07

          Зависит от вашей СУБД, в общем случае, смотря, что выгоднее, так же, как и всегда.

          2. делать «оптимизацию», то получим 1 большой запрос и в маппинге просто результаты будем разгребать.
          но в этом случае будет сложный запрос как в случае с комментами, так и без них. Это тоже плохо.

          Если это для вас плохо, а предыдущий вариант, например, медленный, просто не закладывайте в схему GraphQL таких возможностей. Опять же, GraphQL тут не причем, разделение нагрузки между клиентом и сервером задача каждого проекта.
          3. делать «по-умному»,

          Опять же, зависит от схемы, в данном случае схема может плясать от бэкенда, пойти по пути Rails и сделать автоматическую схему из моделей, со всеми методами (createModel1, updateModel1, deleteModel1), универсальными фильтрами (примерно, как в Mongo posts (filter:{ nameLike: «name» }) ), но с иерархической вложенностью. Такая схема не потребует для поддержки ни строчки кода. Только кастомные запросы, типа авторизации, остальное все автоматически, знай, модели добавляй. Тут пока готовых качественных решений нет, однако биндинги ко многим ORM уже существуют.


          1. AndreyRubankov
            09.08.2017 12:57

            просто не закладывайте в схему GraphQL таких возможностей.
            Спасибо, это уже звучит как ответ.

            т.е. GraphQL подразумевает, что бекенд будет предоставлять какую-то конкретную схему ответа?
            Если так, то это не сильно отличается от какого-то простого HTTP/WEB API, и отличие только в том, что в ответ приходит ограниченный набор данных.


            1. alibertino
              09.08.2017 16:53

              Если так, то это не сильно отличается от какого-то простого HTTP/WEB API, и отличие только в том, что в ответ приходит ограниченный набор данных.

              Так GraphQL и есть язык, т.е. синтаксис, не знаю откуда столько мнений, что это какое-то серверное решение. Видимо, желание иметь серебряную пулю затмевает глаза.


              1. AndreyRubankov
                09.08.2017 17:24

                Я пока не вижу особых достоинств у этой технологии.

                За то, чтобы фронтенд получал меньший объем данных, идет довольно высокая плата в виде QL в URI, а на бекенде и вовсе не понятно что получается. Либо это постоянно гоняется сложный запрос и выгребает все данные из базы и внешних сервисов, либо прячется за какой-то монстроузорный механизм по работе с базой, как кто-то говорил в этом треде, – адаптеры GraphQL к ORM.

                По-моему, крайне небольшое преимущество. И скорее всего, это все будет работать хорошо только в случае: JS -> NodeJS + MongoDB, А в других случаях – от этой технологии будет больше проблем, чем пользы.

                Но, поживем, увидим.


                1. zelenin
                  09.08.2017 17:42

                  высокая плата в виде QL в URI

                  что за плата? что за проблема?


                  Либо это постоянно гоняется сложный запрос и выгребает все данные из базы и внешних сервисов, либо прячется за какой-то монстроузорный механизм по работе с базой, как кто-то говорил в этом треде, – адаптеры GraphQL к ORM.

                  просто работа с базой. в /products?include=comments у вас как-то по другому будет или что?


                  1. AndreyRubankov
                    09.08.2017 17:59

                    что за плата? что за проблема?

                    Как минимум две:
                    1. Длина URI. Часто длина URL должна быть ограничена, я бы даже сказал, что это правило хорошего тона.
                    2. GET запрос с длинным query будет плохо кешироваться транслирующими узлами.
                    Веб это не только Клиент + Сервер, это еще десятки транслирующих и часто по совместительству кеширующих узлов.

                    просто работа с базой. в /products?include=comments у вас как-то по другому будет или что?

                    Да, будет по-другому.
                    Во-первых, не будет необходимости парсить GraphQL и писать свой «Query-engine» для доступа к данным.
                    Во-вторых, URI остается чистым и красивым (не будет проблем, описанных выше).

                    Вы можете считать, что это все надуманные проблемы. Но с другой стороны, GraphQL решает все те же надуманные проблемы типа «сложно расширить модель» или «слишком много данных передается в запросе» ;-)


                    1. zelenin
                      09.08.2017 18:05

                      Да, будет по-другому.
                      Во-первых, не будет необходимости парсить GraphQL и писать свой «Query-engine» для доступа к данным.
                      Во-вторых, URI остается чистым и красивым (не будет проблем, описанных выше).

                      вы ответили на цитату про работу с базой данных вещами, с базой данных не связанными.


                      1. AndreyRubankov
                        09.08.2017 18:30

                        Если про саму СУБД, то в случае HTTP/WEB API, это будет практически всегда один запрос к базе, он будет спроектирован так, чтобы из СУБД не вытаскивать ничего лишнего и чтобы вся агрегация выполнялась на стороне СУБД.

                        В случае с GraphQL, нужно будет поддерживать полное множество всех вариаций запросов, чем больше модель данных – тем сложнее логика для этого будет.

                        Ну, в целом, если плевать на то, как быстро будет работать сервер, и если идти по пути «плевать, докупим еще серверов» – да, это отличная технология. Разработка будет быстрой, проекты будут сдаваться быстро и в срок и все будет круто! =)


                        1. zelenin
                          09.08.2017 18:34

                          я же спросил: в /products?include=comments у вас как-то по другому будет или что?


                          один запрос у вас будет? два? три? почему в graphql другое кол-во запросов будет?


                          В случае с GraphQL, нужно будет поддерживать полное множество всех вариаций запросов, чем больше модель данных – тем сложнее логика для этого будет.

                          Вам так кажется, потому что вы не попробовали.


                          1. VolCh
                            10.08.2017 06:52

                            Грубо, в варианте /products?include=comments будет захардкожено что-то вроде


                            sql = 'SELECT * FROM product';
                            if (request.include === 'comments') {
                            sql = sql + 'INNER JOIN comments ON product.id = comments.product_id';
                            }

                            В варианте с GraphQL, пользуясь референсной или близкой к ней реализацией сервера подобное сделать будет сложнее. Хорошо если малой кровью получится сделать два запроса, а не 1+N


                            1. zelenin
                              10.08.2017 14:41

                              Грубо, в варианте /products?include=comments будет захардкожено что-то вроде

                              именно. если реализация graphql-сервера позволяет на уровне ресолвера узнать запрошенные поля, мы делаем точно так же.


        1. zelenin
          09.08.2017 12:16

          Отличный ответ из разряда: «Проблема на вашей стороне» ;-)

          graphql не предъявляет никаких требований к получению данных, только к структуре готовых данных в ответ на запрос.


          Я не силен в GraphQL особенно со стороны бекенда

          на бэкенде будет ресолвер query Books, который отдаст структуру с данными. Как вы эти данные получите, дело ваше (точно также как в jsonapi реализации /books/:id?include=author,comments). Если вас интересует как это можно сделать в различных языках программирования — это одно. Если в контексте graphql, то этот вопрос не имеет смысла.


          Из всех статей про GraphQL я видел только радостные отзывы, как это удобно для фронтенда и ни разу не видел примеров как это выглядит со стороны бекенда.

          потому что graphql (как и rest) про взаимодействие клиента с апи, а не про реализацию апи на бэкенде. Бэкенды реализуются по разному (можно взглянуть готовые либы на гитхабе).


          1. zelenin
            09.08.2017 12:33

            1. клиент -> 2. запрос -> 3. парсер запроса -> 4. мидлвари (авторизация, кэш, прочая инфраструктура) -> 5. ресолвер (обработчик конкретного типа запроса, извлечение данных) -> 6. Ответ

            Вот типичный флоу, проходящий во время запроса на сервер. Пункты 4 и 5 не относятся к спецификации graphql, и могут реализовываться разработчиком на свое усмотрение.


            1. AndreyRubankov
              09.08.2017 13:03

              т.е. GraphQL – это просто специфичный формат запроса, который в себе будет содержать схему для ответа? и как сказал alibertino, при этом бекенд должен предоставлять конкретную схему ответа.

              правильно ли я понимаю, что у бекенда есть своя модель, а GraphQL лишь говорит, какие данные из той модели нужно отдать клиенту?


              1. zelenin
                09.08.2017 13:43

                у сервера GraphQL есть схема на все данные, клиент запрашивает данные согласно схеме (иначе ошибка валидации — вставить между 3 и 4 пунктами), сервер отдает данные согласно валидному запросу.
                Итого: это язык общения между клиентом и сервером.


        1. VolCh
          09.08.2017 13:26

          Вы можете подсказать, как это должно быть на стороне бекенда?

          Имхо, нет единого "как должно быть"


          У вас есть с этим опыт?

          Помучавшись с GraphQL под PHP перешел от схемы GraphQL<->PHP<->Doctrine<->SQL к GraphQL<->NodeJs<->"REST"<->PHP<-><->Doctrine<->SQL


          1. AndreyRubankov
            09.08.2017 13:47

            Вам не кажется, что если убрать GraphQL и NodeJs ваш API станет понятнее и проще?
            GraphQL<->NodeJs<->"REST"<->PHP<-><->Doctrine<->SQL

            "Web API"<->PHP<-><->Doctrine<->SQL
            в данном случае, Web API делает все то же, что делал бы с GraphQL, только без «QL» в URI запроса.


            1. VolCh
              09.08.2017 13:58

              Что вы имеете в виду под Web API?


              1. AndreyRubankov
                09.08.2017 14:05

                У Вконтакте есть API вида:
                /api/user.get?user_id=34124123&fields=name,age,email
                /api/friends.get?user_id=34124123&limit=30

                Это однозначно не REST, это некий HTTP/WEB API, альтернативно можно назвать RPC.


                1. VolCh
                  09.08.2017 14:10

                  Ну, собственно, Facebook и предлагает GraphQL как один из инструментов создания и использования подобного API.


                1. rraderio
                  10.08.2017 09:05

                  Фишка GraphQL в том что там один ендпоинт, т.е. одним запросом можно выташить не связанные данные, например для /api/friends.get запросить еще и 10 саммых популярных постов не будет очень логично


                  1. AndreyRubankov
                    10.08.2017 09:27

                    Как говорилось выше, не любые данные можно запросить, а лишь те, которые поддерживаются на стороне бекенда.

                    т.е. бекенд реализовывает некую схему, а дальше через GraphQL из этой схемы выбирается только то, что необходимо фронтенду.

                    соответственно, если API изначально но поддерживает выборку постов для запроса на френдов, то и в выдаче их не будет.


                    1. rraderio
                      10.08.2017 10:08

                      соответственно, если API изначально но поддерживает выборку постов для запроса на френдов, то и в выдаче их не будет.

                      Да

                      Но и запрашивать 10 саммых популярных постов в /api/friends.get не будет очень логично


                      1. AndreyRubankov
                        10.08.2017 10:25

                        В этом случае будет создан другой эндпоинт, который будет отдавать френдов с их постами, который будет более логичным. Не так ли?

                        А GraphQL это технология, которая упрощает взаимодействие со сторонними клиентами, про которых мы ничего не знаем и которых мы не можем контролировать. Как у FB или у GitHub.

                        Если API слой не предназначен быть общедоступным, то и GraphQL для него будет избыточным.


                        1. rraderio
                          10.08.2017 10:37

                          В этом случае будет создан другой эндпоинт, который будет отдавать френдов с их постами, который будет более логичным. Не так ли?

                          Т.е. у нас уже есть эндпоинты по отдельности, но если нам нужны эти данные вместе то мы делаем новый эндпоинт, а потом надо сделать еще один эндпоинт для другой комбинации.
                          Так вот, если в GraphQL эти сушности уже есть в схеме, то нам не надо делать новый эндпоинт.


                        1. VolCh
                          10.08.2017 11:26

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


                          Да, GraphQL не уникален в этом отношении в целом, есть и другие конкурирующие технологии, позволяющие не дергать бэкендера для задач типа "нужен один ендпоинт, который возвращает "плоский" список друзей, и другой, который возвращает тот же список, но с постами друзей".


                          1. sentyaev
                            10.08.2017 13:39

                            Один раз описали полную схему данных, а потом только изменяем её, когда она меняется на бэке.

                            Безотносительно REST или GraphQL это как раз самая сложная часть. Если бы, например я, мог вот так взять и за один раз описать полную схему данных, проблем бы у меня не возникло ни с чем, могбы хоть просто данные по сокетам гонять.


                            1. VolCh
                              10.08.2017 14:30

                              Это понятно, что самая сложная часть. Один из плюсов GraphQL как раз не отвлекаться на создание новых ендпоинтов на каждый чих с фронтенда, когда им надо уже имеющиеся данные как-то по другому получить.


                              1. sentyaev
                                10.08.2017 15:12

                                Я уже тут писал, что я пойду и напишу что-нить на GraphQL, чтобы на самом деле разобраться как этот момент разруливается.
                                Но как я понимаю, фронту все равно нужно написать будет GraphQL запрос новый, а бэку все равно придется написать резолвер для этих новых данных.
                                Т.е. я не понимаю пока разницы между добавить новый эндпоинт и использовать его. Те же самые две операции получаются на фронте и на бэке.


                                1. VolCh
                                  10.08.2017 15:39

                                  Допустим у вас есть ендпоинты /users и /posts, возврающие списки юзеров со списком айдишников постов и список постов с айдишниками авторов(юзеров). Фронт работает по схеме типа: берем список постов с сервера, из них выгребаем айдишник автора, и берем по нему ФИО автора с сервера. 10 постов показать надо — делаем 11 запросов. На уровне бэка это всё связано, но вот просто такие ендпоинты. Спецы по UX и фронтендеры посовещались и пришли к вам просить сделать новый ендпоинт /posts-with-authors. Знакомо? В случае GraphQL они к вам не пойдут, а сразу сделают, а ещё вероятне фроендерам сразу по рукам надают когда они 11 запросов сделают.


                                  1. sentyaev
                                    10.08.2017 16:14
                                    +1

                                    Спецы по UX и фронтендеры посовещались и пришли к вам просить сделать новый ендпоинт /posts-with-authors. Знакомо?

                                    Нет, не знакомо. За такой api разработчика нужно отправлять учить матчасть.

                                    Вы опять описываете случай когда api это просто способ доступа ка табличкам/коллекциям базы данных. Это называется anemic api, и от него у всех теже проблемы как и от anemic domain model. Если раньше мы спорили как нам делать модель данных, то теперь споры перешли на то как нам делать api.

                                    Если раньше мы использовали нашь домен в контроллерах и потом отдавали некую модель во view, то теперь все тоже самое только модель мы отдаем через http, а SPA уже рисует как хочет.
                                    Во времена когда небыло SPA, проблемы были теже — недостаточно данных, N+1 и т.д. Просто они не стояли так остро, всетаки про тот же N+1 нам не нужно было делать несколько запроств от клиетна к серверу. Да что говорить, проблема N+1 была даже когда вся логика была в хранимых процедурах.

                                    Суть в том, что проблемы нужно решать не фреймворками, а мозгом. И да, иногда проще сначала сделать прототип у которого будут проблемы с избыточностью данных и скоростью доступа, а потом уже переделать нормально (если нужно, может и так будет good enough).

                                    А про /users & /posts, я бы просто вместо списка id's авторов, возвращал
                                    /posts
                                    [
                                      {
                                        ...post properties...,
                                        authors: [{
                                          id: author_id,
                                          name: 'Franz Kafka'
                                        }]
                                      }
                                    ]
                                    


                                    Ну а если нам нужна полная информация по авторам для определенного поста, я бы добавил:

                                    /posts/{post_id}/authors


                                    1. rraderio
                                      10.08.2017 16:25

                                      А если к постам нужны не только авторы, но и коментарии и профили коментаторов? Тоже все в /posts?


                                      1. sentyaev
                                        10.08.2017 16:47
                                        +1

                                        Зачем вы так. Вы же сами прекрасно понимаете, что вам это все в /posts не нужно.
                                        Давайте смотреть от вариантов использования.
                                        Когда вы отображаете Пост, что главное? Как можно быстрее отобразить сам контент этого поста, чтобы пользователь мог начать его читать.

                                        Ну а все эти комментарии, а тем более профили комментаторов вам даже не нужны. Профиль комментатора вы вообще можете не загружать, а добыть его только когда пользователь на этого комментатора мышку наведет или кликнет.

                                        В этом случае запросить все данные одним скопом — худшая идея.

                                        Когда я работал в компании по продаже отелей, у нас была похожая задача.
                                        Страница отеля. Так там сначала на сервере мы генерили страницу с опсанием отеля и картинкаи, чтобы ее отобразить максимально быстро, а уже потом делали несколько запросов на доступность номеров и всякую дополнительную фигню типа «похожие отели», «лучшие в городе» и т.д.


                                        1. rraderio
                                          10.08.2017 17:04

                                          Когда вы отображаете Пост, что главное? Как можно быстрее отобразить сам контент этого поста, чтобы пользователь мог начать его читать.

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

                                          Даже тут на хабре есть id, name, avatar коментатора


                                          1. sentyaev
                                            10.08.2017 17:27

                                            Интересно вы от простой задачи с /posts & /authors перешли к тому как сделать хабрахабр. Я не эксперт по проектированию блог движков. Я только умею про отели, билеты и спорт делать.


                                            1. rraderio
                                              10.08.2017 17:35

                                              Хабр как пример что такой запрос нужен в реальных приложениях.
                                              Комментрии тут, это часть контента, и их нельзя подтягивать, т.к. тогда поисковики их не проиндекируют. Так что не всегда возможно подтянуть данные.


                                              1. sentyaev
                                                10.08.2017 17:49

                                                Хабр всетаки не SPA, но я могу предположить, что бэкэнд делает как минимум два запроса в разные хранилища для отображения этой страницы.
                                                Первый — достать пост.
                                                Второй — достать комменты.
                                                Ну а потом уже склеить и отобразить.

                                                То что я вижу на других блогах, это обычно сначала отображается пост, а когда докручиваешь до конца, то начинают загружаться комменты.
                                                Некоторые сворачивают ветки и их нжуно по клику догружать.
                                                Некоторые отображают только первые несколько комментов.

                                                Ну и если говорить о нужности такого запроса то она сомнительна, вряли вы будете блог на SPA делать. Блог это плохой пример.
                                                Я, если честно, даже не знаю какой пример для SPA хороший. У меня всего один проект с полностью SPA приложением. Все остальные это классические веб-приложения, но на некоторых страницах используется knokout, react или angular. Т.е. бывает что одна страница может быть как одно приложение, а другая как другое.


                                        1. VolCh
                                          10.08.2017 18:48

                                          Давайте смотреть от вариантов использования.

                                          Вот собственно REST-подобный подход требует по одному ендпоинту для каждого варианта использования, если им требуются разные наборы данных и мы беспокоимся о каждом лишнем байте. GraphQL предполагает, что фронт будет запрашивать только необходимые ему поля для каждого конкретного случая.


                                          1. sentyaev
                                            11.08.2017 04:43

                                            Вот собственно REST-подобный подход требует по одному ендпоинту для каждого варианта использования

                                            Так и в GraphQL продется писать отдельные query и имплементацию на бэкэнде.

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

                                            Ну и да, пока что я вижу только одну фичу GraphQL — это отдать тлько те данные которые запросили, но это нужно только очень большим компаниям которым нужно экономить на трафике, т.е. мы уже говорим не о миллионах пользователей, а о десятках, а может даже и сотнях миллионах пользователей.
                                            В общем мое мнение простое, GraphQL решает несуществующие проблемы и толкает людей делать очень плохие api (я имею ввиду anemic api), перенося часть бизнес логики на клиента.
                                            Читая все комментарии я вижу что у программистов есть проблема — фрон разработчики пытаются противопоставить себя бэк разработчикам, и вместо того чтобы работать вместе, пытаются работать раздельно, чтобы даже не пересекаться. В итоге это выливается в такое — просто дайте нам доступ к базе, а дальше мы сами.

                                            Мы это уже проходили, сначала все было в хранимках и были DBA, теперь их както меньше, все используют ORM. Теперь вот с распространением SPA и приложений для мобильников это все перетягивается на фронт.


                                            1. VolCh
                                              11.08.2017 07:32

                                              Так и в GraphQL продется писать отдельные query и имплементацию на бэкэнде.

                                              Не совсем так. Грубо говоря, для GraphQL надо написать отдельный query для корней агрегатов, но не надо писать отдельные для "пост с авторами", "пост с комментариями", "пост и с авторами, и с комментариями".


                                              Ну и да, пока что я вижу только одну фичу GraphQL — это отдать тлько те данные которые запросили, но это нужно только очень большим компаниям которым нужно экономить на трафике

                                              Экономия трафика для моих проектов — бесплатный бонус. Основной плюс — не надо изменять бэкенд когда фронтенду нужно было 7 полей из 20 имеющихся в "базе", а теперь нужно 15. И если на плоских структурах можно просто отдавать все поля сразу, то на иерархических отдавать весь граф неразумно, а на циклических просто невозможно (в рамках JSON).


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

                                              Тут не противопоставление фронта и бэка, тут снижение их взаимной зависимости, распараллеливание задач, снижение числа ситуаций, когда бэкендеру нужно всё бросать и срочно делать очередной ендпоинт для фронта, потому его отсуствие блокирует их работу. И даже если один пишешь всю задачу и на фронте, и на бэке, то меньше нужно переключать контекст.


                                              Мы это уже проходили, сначала все было в хранимках и были DBA, теперь их както меньше, все используют ORM.

                                              Всю жизнь сам писал и хранимки, и "обычный" код. С приходом ORM в массы, хранимки, триггеры, вьюшки и т. п. пишу лишь в исключительных случаях, когда, они дают неоспоримое преимущество. Основная причина — SQL-логика сложнее в поддержке, прежде всего в плане инструментария.


                                              1. sentyaev
                                                12.08.2017 03:44

                                                Не совсем так. Грубо говоря, для GraphQL надо написать отдельный query для корней агрегатов, но не надо писать отдельные для «пост с авторами», «пост с комментариями», «пост и с авторами, и с комментариями».

                                                Мы уже это обсуждали, это зависит от того как api спроектирован и как нам эти данные нужно получить. Тут сложно сказать как лучше, нужно смотреть каждый конкретный пример.

                                                Экономия трафика для моих проектов — бесплатный бонус. Основной плюс — не надо изменять бэкенд когда фронтенду нужно было 7 полей из 20 имеющихся в «базе», а теперь нужно 15.

                                                Это не совсем бесплатный бонус, вы теряете возможность кэширования (не совсем теряете, но теперь это становится очень сложной задачей, может конечно для когото и не сложной, но как минимум работы добавится).

                                                И если на плоских структурах можно просто отдавать все поля сразу, то на иерархических отдавать весь граф неразумно, а на циклических просто невозможно (в рамках JSON).

                                                Как отдавать данные это опять же вопрос дизайна api.
                                                Про циклические данные я не понял, могли бы вы ткнуть меня носом как эта проблема (которой у меня не было) решается в GraphQL?

                                                Тут не противопоставление фронта и бэка, тут снижение их взаимной зависимости… и т.д.

                                                Мы же уже это обсуждали, в любом случае писать резолверы, и если в модели изначально небыло поля его все равно добавлять. Почему вы предполагаете, что если GraphQL, то модели api у нас вседа идеальны и не требуют расширения или изменения, а если REST, то у нас все плохо?

                                                Всю жизнь сам писал и хранимки, и «обычный» код. С приходом ORM в массы, хранимки, триггеры, вьюшки и т. п. пишу лишь в исключительных случаях, когда, они дают неоспоримое преимущество. Основная причина — SQL-логика сложнее в поддержке, прежде всего в плане инструментария.

                                                Это да. Сейчас развиваются решения «backend as service», например Firebase (была еще какая-то но ее вроде убили). Я считаю, что для определенного класса задач/приложений это может работать. Да и возможно, что GraphQL в этом случае действительно даст преимущество в скорости разработки и поддержки. Но у меня пока не сложилось четкое и определенное мнение об этом.
                                                Я думаю это хорошо сработает для приложений у которых вся логика на клиенте (например игры), и бэкэнд нужен скорее для сохранения состояния и его синхронизации.

                                                Я же всегда делал приложения где вся логика на бэкэнде, а api это просто мелкая прослойка чтобы данные отдать и команды принять.
                                                Ну и опять же, один ресурс может отдавать разные модели, например:
                                                /posts
                                                может вернуть PostReference, Post, PostWithComments,
                                                используя разные типы, такие как
                                                application/vnd.post-ref+json, application/vnd.post+json и т.д.


                                                1. VolCh
                                                  13.08.2017 16:06

                                                  Это не совсем бесплатный бонус, вы теряете возможность кэширования

                                                  Нашим процессам кэширование скорее противопоказано. Может, конечно, пользователь жать F5, но при нормальном флоу как раз постоянно происходят изменения состояния — суть пользовательских сценарие в изменении.


                                                  Про циклические данные я не понял, могли бы вы ткнуть меня носом как эта проблема (которой у меня не было) решается в GraphQL?

                                                  Классический пример — пользователь и его друзья, тоже пользователи. При разработке классического API мы для конкретного ендпоинта вынуждены искусственно ограничивать глубину просмотра клиентом друзей на бэкенде по, грубо говоря, определению ендпоинта. В GraphQL или JSON API (тоже далеко не чистый REST) клиент сам указывает необходимую ему глубину просмотра.


                                                  Почему вы предполагаете, что если GraphQL, то модели api у нас вседа идеальны и не требуют расширения или изменения, а если REST, то у нас все плохо?

                                                  Я предполагаю, что модели одинаковы, но в случае REST всё наружу не выведено через API в целях оптимизации трафика.


                                                  Я думаю это хорошо сработает для приложений у которых вся логика на клиенте (например игры), и бэкэнд нужен скорее для сохранения состояния и его синхронизации.

                                                  Как по мне, то ровно наоборот. REST хорош как раз для сохранения/синхронизаций состояний. Получил "снэпшот" ресурса по GET, что-то намодифицировал и отправил новый "снэпшот" по PUT или "дифф" по PATCH. GraphQL же как раз заточен (в плане модификации) под точечные бизнес-операции, позволяя избегать костылей типа POST /posts/123/approve c пустым телом.


                                                  Ну и опять же, один ресурс может отдавать разные модели, например:
                                                  /posts
                                                  может вернуть PostReference, Post, PostWithComments,
                                                  используя разные типы, такие как
                                                  application/vnd.post-ref+json, application/vnd.post+json и т.д.

                                                  Можно считать GraphQL более гибким и простым (как минимум на фронте) способом делать это.


                                      1. sentyaev
                                        10.08.2017 16:49

                                        У меня вообще ощущение, что тут все обсуждают какието простые CRUD приложения, в которых на самом деле вообще ничего делать не нужно. В любом фреймворке можно почти бесплатно получть все вьюхи, их нужно просто раскрасить потом. И местами чутка кастомизировать.


                                  1. AndreyRubankov
                                    11.08.2017 21:31

                                    Допустим у вас есть ендпоинты /users и /posts, возврающие списки юзеров со списком айдишников постов и список постов с айдишниками авторов(юзеров). Фронт работает по схеме типа: берем список постов с сервера, из них выгребаем айдишник автора, и берем по нему ФИО автора с сервера. 10 постов показать надо — делаем 11 запросов.

                                    Лично я бы почитал требования по проекту, и сделал бы эндпоинт /feed, который будет возвращать посты постранично со всеми необходимыми данными для отображения.

                                    В крайнем случае, я бы сделал batch эндпоинты для получения данных:
                                    /user/list?ids=1,2,3
                                    /post/list?ids=1,2,3
                                    в этом случае запросов будет всего 2.

                                    Спецы по UX и фронтендеры посовещались и пришли к вам просить сделать новый ендпоинт /posts-with-authors. Знакомо?

                                    К счастью в команде, где люди хоть чуть-чуть понимают что делают, такое бывает крайне редко.

                                    В случае GraphQL они к вам не пойдут, а сразу сделают
                                    В случае с GraphQL у них будут все те же /users и /posts, которые они смогут запрашивать через GraphQL. Ни один вменяемый бекенд девелопер и тем более архитектор (или тех.лид) не позволит сделать схему, в которой будут все возможные данные. Потому что эта херь сразу завалится при более-менее нормальной нагрузке.


                                    1. sentyaev
                                      12.08.2017 03:45
                                      +1

                                      В крайнем случае, я бы сделал batch эндпоинты для получения данных:
                                      /user/list?ids=1,2,3
                                      /post/list?ids=1,2,3
                                      в этом случае запросов будет всего 2.


                                      Это плохой дизайн, именно поэтому и не любят REST.


        1. rraderio
          09.08.2017 13:33

          При девелопменте используем любые запросы, на бекенде делаем в лоб.
          На проде используем только предварительно одобренные запросы, которые уже можно оптимизировать так как запросы не могут быть любыми.


          1. AndreyRubankov
            09.08.2017 13:41

            В результате у вас конкретный API, который мы можете дергать, он получается не такой уж и гибкий.
            В чем тогда преимущество перед обычным «Web API»?


            1. rraderio
              09.08.2017 13:50

              В девелопменте он гибкий и фронтенд не должен каждый раз просить бекенд добавить новые поля или новый ендпоинт


              1. AndreyRubankov
                09.08.2017 13:55

                Учитывая, что бекенду нужно все так же делать маппинг и создавать все ту же схему данных ( как сказал zelenin в https://habrahabr.ru/post/335158/?reply_to=10351014#comment_10350990 ), то получается, что не так уж это и гибко, как вы говорите.

                Если в модели нету дополнительных полей, бекенду нужно будет их добавлять (расширять схему).


                1. rraderio
                  09.08.2017 14:02

                  Расширять схему надо будет намного реже, чем в REST или RPC добавлять новые ендроинты, так как часто нужны почти те же данные, соответственно для каждой комбинации по отдельному ендпоинту


                1. VolCh
                  09.08.2017 14:08

                  Гибкий он ситуациях, когда модель данных покрывает бизнес-потребности, но на фронте полная модель не нужна. В традиционной модели два подхода основных:


                  • отдаём клиенту всё, что имеем, а он уже разбирается что ему нужно, игнорируя лишнее при обработке ответа на запрос (легко перевалить разумные ограничения на размер ответа)
                  • для каждого кейса отдельный ендпоинт со строго необходимым фронту набором полей, который при необходимсти расширяется.

                  GraphQL (а такжеJSON API и подобные стандарты) предлагают третий путь — клиент имеет доступ ко всей модели, но реально запрашивает только то, что ему нужно. Сказал бизнес "Вот в карточке продукта у нас есть поле "последняя дата входа в систему учетной записи пользователя, последний раз редактировашего продукт", добавьте его колонкой в список продуктов — бэкенд при этом не затрагивается, а объём передавемых данных был и остаётся близким к минимально необходимому (с учетом потребностей HTTP и JSON).


  1. rumatavz
    09.08.2017 10:25

    Коллеги, а правда написано вот в этой статье https://www.progress.com/blogs/rest-api-industry-debate-odata-vs-graphql-vs-ords что в GraphQL нет фильтрации?

    Ну то есть что то в духе
    GET serviceRoot/People?$filter=FirstName eq 'Scott'
    GET serviceRoot/Airports?$filter=contains(Location/Address, 'San Francisco')


    1. zelenin
      09.08.2017 11:37
      +1

      в graphql есть аргументы в запросах:


      query {
        People(FirstName: "Scott") {
          .. // fields
        }
      }


      1. vintage
        14.08.2017 10:01

        И как сделать возможность фильтрации по любому из 10 полей с любым из 10 предикатов (равно, больше, меньше, не больше, не меньше, между, включает и тд) с возможностью повторения полей (например, вхождение в один из нескольких диапазонов)?


        1. zelenin
          14.08.2017 10:47

          согласно реализации. сама спецификация не описывает варианты использования артибутов.


          1. vintage
            14.08.2017 14:40

            Не уходите от ответа. Как такое можно реализовать? Свой язык запросов в параметре Filter?


            1. zelenin
              14.08.2017 14:42

              я не ухожу от ответа — я прямо говорю: спецификация это не описывает.


        1. arvitaly
          14.08.2017 15:50

          Никаких проблем сделать это на GraphQL нет

          query {
              People(
                  Age: { and: [ { between: [15,16] }, {between: [20, 30] } ]  }
              )
          }
          

          Но делать что-то настолько универсальное нужно с очень большой оглядкой на бэкенд. Это удобно на этапе проектирования, но в production лучше уже нести более конкретную схему.


          1. vintage
            14.08.2017 19:37

            Спасибо, то есть аргументом может быть произвольный JSON. Не понятно тогда зачем было вводить множественные именованные аргументы, если можно было бы всегда принимать один аргумент JSON вида.


            1. zelenin
              14.08.2017 19:46

              1. это не json, а объект в терминах grapqhl
              2. аргументы разным целям служат, где-то фильттр, где-то сортировка, где-то служебный флаг итд. Вообще во всех языках в функции передается список аргументов, а не массив.


              1. vintage
                14.08.2017 20:28

                Речь о том, что можно было бы сделать так и не вносить лишних сущностей:


                query {
                    People({
                        Age: { and: [ { between: [15,16] }, {between: [20, 30] } ]  }
                    })
                    Book(123)
                }


                1. zelenin
                  14.08.2017 20:32

                  ну в любом языке можно было бы сделать


                  func GetPeople(object)

                  вместо


                  func GetPeople(var1, var2, var3)

                  но семантика и все такое — поддерживается второй вариант, и в его рамках первый.


  1. sentyaev
    09.08.2017 10:25

    bevalorous а могли бы вы в разделе «Обработчики маршрутов и распознаватели» описать пример с Авторами, Книгами и Комментариями. А то про фронт вы очень хорошо рассказали, а про бэк ограничились Хелловордом.


    1. bevalorous Автор
      09.08.2017 16:39

      Я бы с удовольствием, но эта статья — перевод.


      1. sentyaev
        09.08.2017 17:17

        Ах… прошу прощения, не увидел что перевод.


  1. NikitOS9
    09.08.2017 11:27

    графкул очередной(внеочередной) посредник между серваком/клиентом. (лишний имхо)
    непохож как данные хранятся на серваке ни как они нужны на клиенте, типа такой вот оригинально-абстрактный, его нужно выдумать/спроектировать, поддерживать отдельно от остальных.
    читаем данные из нормализованной(или не очень, может вообще nosql) базы, пихаем все это в графкул, передаем на клиента и переделываем там в нужный по ему формат…

    зачем вся это возня… и причем тут graph, с графами какая связь то?


    1. KirEv
      09.08.2017 11:46

      По моему в подобных статьях часто путают, как выше в комментах писали, предлагают graphql как замену ресту, привычным ендпоинтам и т.п.,

      А оно же из названия все понятно: data(graph) query lenguage.

      Если данные в проекте представленны в виде графов — скорее всего graphql подойдет лучше всего для манипуляции данными, в фейсбуке видимо по этой причине и заморочились чтобы облегчить свои будни, исходили из потребностей бизнес-задач.

      Юзать графкл вместо обычного реста для апи среднего приложения, или пусть большого, где графами и не пахнет — это боль и ад… технология ради технологии для экономии на спичках

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


      1. napa3um
        09.08.2017 11:55

        Да, похоже, большинство споров о хайповом продвижении GraphQL «для всего», а не об реальном использовании в конкретных задачах. Данная статья как раз такая — «почему технология А лучше технологии Б» вместо «в каких задачах и как удобно применять технологию Б».


  1. rraderio
    09.08.2017 13:13

    А как там дела с ролями/правами на допуск?
    Множество вещей, которые клиент не должен видеть, часто на основе ролей запрашивающего пользователя.

    Как это задокументировать в GraphQL?


    1. VolCh
      09.08.2017 13:28

      А как там дела с ролями/правами на допуск?

      Так же как и в "REST" — всё на вашей совести


      1. rraderio
        09.08.2017 13:38

        Ну, в документации REST API я могу указать какие права надо иметь для каждого ендпоинта, а тут только 1 ендпоинт, вот мне и интерестно как клиенты узнабю что нужны какие-то права если этого нет в документации?


        1. zelenin
          09.08.2017 13:49

          в rest у вас эндпойнты, в graph — типы query/mutation и соответствующие им ресолверы.


          1. rraderio
            09.08.2017 13:56

            Ну и как мне задокументировать что для какой-то коллекции нужны какие-то права?


            1. zelenin
              09.08.2017 13:57

              а как вы в rest это делаете?


              1. rraderio
                09.08.2017 14:07

                в документации REST API я могу указать какие права надо иметь для каждого ендпоинта


                1. zelenin
                  09.08.2017 14:08

                  в документации GraphQL API укажите какие права надо иметь для каждого типа запросов


                  1. rraderio
                    09.08.2017 14:24

                    Супер, а как это сделать, есть какие-то тулзы? Для REST мы используем Swagger и там можно указать права.


                    1. zelenin
                      09.08.2017 14:28
                      +1

                      не знаю, погуглите. это не часть спеки, как и не часть rest.


                    1. alibertino
                      09.08.2017 17:00

                      http://facebook.github.io/graphql/#sec-General-Principles


                      1. rraderio
                        09.08.2017 17:06

                        М, что-то не могу найти, какой пункт?


                    1. asci
                      09.08.2017 18:15

                      у graphql есть тулза (интерактивная документация) https://github.com/graphql/graphiql у ваших резолверов есть поле Description (если брать expressjs реализацию), туда и пишите вашу документацию


  1. greendimka
    09.08.2017 13:38

    В восемьсоттридцатьчетвёртый раз:

    • REST = RPC — используем для вызовов методов API
    • OData/GraphQL = SQL — используем для запросов к данным


    Поражаюсь стремлению людей усложнять понятные парадигмы.


    1. rraderio
      09.08.2017 13:44

      В GraphQL есть мутации, т.е. не только запрашивать но и изменять данные


    1. leschenko
      09.08.2017 13:53

      REST != RPC

      RPC — удаленное выполнение некой логики. Грубо говоря — сервер, сделай там что-то и скажи что получилось.
      REST — передача состояния между клиентом и сервером. не подразумевает каких-то тяжелых рассчетов. Грубо говоря — CRUD.

      OData\GraphQL\FQL и т.д. — это только R из CRUD, который REST


      1. VolCh
        09.08.2017 14:13

        GraphQL точно имеет поддержку всеможных мутаций, то есть встроенный механизм RPC именно в виде "сервер, сделай там что-то и скажи что получилось, причём скажи только интересующие нас здесь и сейчас детали, а не всё что ты можешь сказать по этому поводу".


      1. vintage
        14.08.2017 10:07

        Очевидно же, что ту имела ввиду не эквивалентность, а расположенность на одном уровне абстракций.


  1. sasha1024
    09.08.2017 14:12
    -1

    Очевиднейшая идея.
    Тормозится исключительно отсутствием полных, удобных и популярных фреймворков для этого.
    Ну ещё, возможно, отсутствием полной, быстрой и популярной объектной СУБД (реляционные — гениальная идея, но устарела N десятилетий назад).


  1. sergiobelya
    09.08.2017 15:41

    Имхо, давать фронтендщикам (при всём огромнейшем уважении к ним) писать запросы к БД посредством GraphQL (в статье об этом ни слова но в конечном счёте это так), нужны очень веские основания для этого и соответствующий уровень фронтендщиков (которые понимают как работает бэкенд и база).
    Идея, конечно, интересная, отдать все нужные фронтенду данные одним запросом. НО. Всегда ли это нужно? Когда меня об этом просят, я начинаю задавать уточняющие вопросы, и очень часто оказывается, что не так уж и нужно, просто чуть удобнее (или так кажется), зато часто будет большой оверхед по производительности на сервере и клиенте (да-да, в т.ч. в браузере, хотя я понимаю, что GraphQL изначально предназначен снижать оверхед, но это очень сильно от рук зависит).
    В тех случаях, когда действительно нужно в одном запросе отдать связанные данные, ок — это не проблема и в обычном REST. Не отдавать не нужные данные — тоже при необходимости оптимизации траффика реализуется.
    К тому же, когда GraphQL API доступно в мир, там реально могут легко атаковать твой сервер на отказ от обслуживания сложными запросами. Т.е. даже знание бэкенд-разработчиком ВСЕХ видов запросов, которые составляет фронт-енд, не спасёт.
    Я конечно раньше про это не читал, и могу ошибаться, но пока с моей колокольни выводы такие, не судите строго.


    1. zelenin
      09.08.2017 16:50

      Имхо, давать фронтендщикам (при всём огромнейшем уважении к ним) писать запросы к БД посредством GraphQL (в статье об этом ни слова но в конечном счёте это так)

      нет, это не так


      В тех случаях, когда действительно нужно в одном запросе отдать связанные данные, ок — это не проблема и в обычном REST

      но не существует спецификации


      К тому же, когда GraphQL API доступно в мир, там реально могут легко атаковать твой сервер на отказ от обслуживания сложными запросами

      GraphQL не подразумевает сложных запросов. Он подразумевает язык общения между клиентом и сервером.


      1. sentyaev
        09.08.2017 17:31

        но не существует спецификации

        У вас есть REST API, есть документация, она и является спецификацией.
        Есть Swagger, там и модели вам и документация и можно за все места API подергать и клиента сгенерить.
        В общем столько вопросов возникает как раз потому, что я да и другие участники дискуссии не понимают в чем преимущество этого GraphQL. Да его и нет. Все аргументы это же просто вкусовщина.
        Профит может быть только для действительно большой компании с колоссальной нагрузкой и большим количеством ресурсов чтобы эту балалайку поддерживать.


      1. AndreyRubankov
        09.08.2017 18:06

        GraphQL не подразумевает сложных запросов. Он подразумевает язык общения между клиентом и сервером.
        Таки это и подразумевает.
        Вы пишите запрос к серверу «дай мне кучу данные вот таких и таких с такими фильтрами», и сервер начинает тужится выгребать и фильтровать их.
        Сортировка и Группировка в GraphQL есть? – еще лучше, прям раздолье для повышенной нагрузки на сервер!

        Вы описываете список данных, которых нету в схеме, и тут что-то должно произойти: тихо ничего не вернуть? или выдать какую-то ошибку, что таких полей нету?


        1. zelenin
          09.08.2017 18:39

          Вы пишите запрос к серверу «дай мне кучу данные вот таких и таких с такими фильтрами», и сервер начинает тужится выгребать и фильтровать их.

          сервер начинает делать то же, чтобы делал в rest. Вы попробуйте уже наконец.


          Сортировка и Группировка в GraphQL есть? – еще лучше, прям раздолье для повышенной нагрузки на сервер!

          а в чем проблема? конечно есть, как и везде.


          Вы описываете список данных, которых нету в схеме, и тут что-то должно произойти: тихо ничего не вернуть?

          согласно спецификации. провалидировать, вернуть ошибки.


          1. napa3um
            09.08.2017 18:52

            > сервер начинает делать то же, чтобы делал в rest. Вы попробуйте уже наконец.

            В общем случае — нет, REST «заставит» вас правильно разложить персистентные модели на ресурсы для быстрой их отдачи, «естественным» образом подтолкнёт к реализации соответствующей денормализации данных и инкапсуляции всех долгих агрегаций и вычислений за ресурсами типа «операция». Да, это требует больше усилий в проектировании, а GraphQL позволяет заняться этим позже, но этим заняться всё равно придётся (если проект «выстрелит», да, потому для прототипирования MVP для привлечения первичных инвестиций, наверное, GraphQL хорош).

            > а в чем проблема? конечно есть, как и везде.

            Это примерно как вместо бэкэнда просто расшарить клиентам БД и заниматься композицией данных на клиенте. Кажется поначалу неплохой идеей (экономия на бэкенде, пусть фронтендщики и гуй рисуют, и данные себе структурируют), но в итоге приводит к «отсутствию» архитектуры.


            1. zelenin
              09.08.2017 18:55

              если проект выстрелит, то у меня будет денормализованное хранилище, а не sql с join'ами.
              Опять обсуждаем хранилище в обсуждении языка запросов.


              1. napa3um
                09.08.2017 18:58

                Денормализация вообще безотносительно реляционности хранилища имелась ввиду. И, главное, вы поняли точку зрения? Чтобы не продолжать этот бесконечный спор, ибо вы просто не видите тех сложностей, о которых вам говорят оппоненты, и оно, может, и к лучшему, значит, ваши проекты, действительно, совместимы с GraphQL, полюбившимся и удобным для вас инструментом.


                1. zelenin
                  09.08.2017 19:05

                  Денормализация вообще безотносительно реляционности хранилища имелась ввиду.

                  мной тоже.


                  И, главное, вы поняли точку зрения?

                  конечно понял — вы в очередной раз обсуждаете то, что к graphql не относится.


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

                  эти сложности не являются следствием использования graphql, и аналогично присутствуют (и решаются) в rest. Вот что оппоненты не хотят видеть, поскольку 99% не поняли что это такое, и как вообще это работает, хотя демки с кодом гуглятся на раз-два.


                  1. napa3um
                    09.08.2017 19:10

                    Оппоненты вам говорят, что решая эти проблемы с GraphQL (и оппоненты их решали, не думайте, что обсуждается конь в вакууме), вы в итоге получите REST, без всех гибкостей, которые, вроде как, позиционируются преимуществом GraphQL. Только и всего. (Да, для быстрого старта разработки это может иметь смысл, с этим не спорю.)


                    1. zelenin
                      09.08.2017 19:18

                      Оппоненты вам говорят, что решая эти проблемы с GraphQL (и оппоненты их решали, не думайте, что обсуждается конь в вакууме), вы в итоге получите REST, без всех гибкостей

                      какие эти проблемы? которые с graphql не связаны? прикрутить авторизацию? кэширование? проверка на уровни вложенности? как все это сделает из graphql rest?


                      и оппоненты их решали, не думайте, что обсуждается конь в вакууме

                      не надо говорить за оппонентов — никто из критиков здесь не то, что не решал, а даже не трогал graphql на деле.


                      1. napa3um
                        09.08.2017 19:45

                        REST — это архитектурный паттерн (даже мета-архитектурный — это набор ограничений для построения собственной архитектуры), накладывающий ограничения и на протокол, и на представление API сервера (в виде ресурсов с фиксированным набором действий над ними), и обосновывающий это всё математикой (сокращением вероятности неконсистентных между собой состояний клиента и сервера и увеличением контроля над этими ситуациями). REST — это «инструкция» по тому, как строить веб-приложение. А GraphQL — это способ не забивать себе этим всем голову, а просто расшарить БД фронтендеру. И по мере усложнения композиций данных, собираемых на клиенте, сталкиваясь с проблемами обеспечения актуальности и непротиворечивости разных кусков моделей, неявно собираемых бэкендом с GraphQL, а может и пытаясь горизонтально отмасштабировать проект, программист так или иначе придёт ко всем тем проблемам, которые и решались Филдингом в его диссере о REST. GraphQL — это способ пройти путь Филдинга, набив собственные шишки, но зато очень быстро начав, сразу с готовой библиотеки с низким порогом вхождения (и раньше получив видимый результат для инвесторов). GraphQL — это способ экономить большим корпорациям, уменьшая требования к квалификации программистов (и это не оскорбление, это то, к чему стремится каждый программист — упрощение своей работы). Это не плохо или хорошо, это просто иной подход, в какой-то ситуации он может быть и оправдан (например, если вы — Facebook с штатом на триллион программистов, или если прототипируете MVP, или вам ну просто по каким-то причинам недоступен отдельный квалифицированный бэк-программист).


                        1. zelenin
                          09.08.2017 19:54

                          А GraphQL — это способ не забивать себе этим всем голову, а просто расшарить БД фронтендеру.

                          вот в этом у вас и непонимание. Это попытка переиначить язык запросов между клиентом и сервером для упрощения этого взаимодействия.


                          опять же не вижу аргументации, кроме общефилософских измышлений, что намекает, что ваше мнение также основано на вашем понимании проблемы, а не на ее реальной сути.
                          Если есть что-то конкретное сказать, давайте общаться — у меня реальные проекты и на rest и на graphql.


                          1. napa3um
                            09.08.2017 20:07

                            > Это попытка переиначить язык запросов между клиентом и сервером для упрощения этого взаимодействия.

                            Вы как бы кратко прорезюмировали всё то, что я написал в предыдущем комментарии :).

                            > опять же не вижу аргументации, кроме общефилософских измышлений

                            Да, потому что и проблема «философская» (о способах построения архитектуры и ограничениях, которые помогают это сделать, либо эти ограничения можно будет вывести самостоятельно, описывая взаимодействие между клиентом и сервером более «вольным» языком GraphQL и не понимая, почему в одном месте страницы, например, обновился счётчик, а в другом нет, и лишь затем придя к необходимости выделения отдельной репрезентации «страница такая-то», а не неявной её сборки из кучи персистентных моделей, которые клиенту вообще не должны быть видны).

                            > Если есть что-то конкретное сказать, давайте общаться — у меня реальные проекты и на rest и на graphql.

                            О чём общаться? Какую конкретику вы имеете ввиду? Тут проблема в общем подходе, а не в отдельных сравнениях каких-нибудь параметров запросов или способах масштабирования, просто перекладывание части бизнес-логики на язык запросов между клиентом и сервером. (Не абсолютная проблема, а, скорее, особенность, GraphQL — просто инструмент сокращения количества архитектурных слоёв в приложении путём «ленивого» проектирования этих слоёв «потом»).

                            Надеюсь, точка зрения понятна, и понятно, что оспаривать её нет смысла, она просто может вам либо нравиться, либо нет :).


                        1. VolCh
                          10.08.2017 06:57

                          или вам ну просто по каким-то причинам недоступен отдельный квалифицированный бэк-программист

                          Или не хочется нагружать квалифицированного бэк-программиста задачами "а вот тут сделай нам отдельный ендпоинт для комментариев первого уровня, а вот тут сделай нам ендпоинт для дерева комментариев начиная с этого, а вот тут для поста и всех деревьев комментариев"


                    1. sasha1024
                      12.08.2017 02:13

                      вы в итоге получите REST, без всех гибкостей
                      Не совсем. GraphQL в общем случае можно считать надмножеством REST, как его классически реализуют; всё то, что можно получить при REST, позволяет и GraphQL; но GraphQL позволяет на ходу строить и более сложные запросы. Да, бо?льшая часть гибкости GraphQL окажется невостребованной, но не вся.


                      1. napa3um
                        12.08.2017 05:40

                        > Не совсем. GraphQL в общем случае можно считать надмножеством REST

                        REST и RPC взаимовыразимы друг через друга, но являются принципиально различными подходами к проектированию API.

                        > всё то, что можно получить при REST, позволяет и GraphQL

                        Всё то, что можно получить при Haskell и C++, позволяют и ассемблер или машинные коды.

                        > Да, бо?льшая часть гибкости GraphQL окажется невостребованной, но не вся.

                        Например?


      1. sergiobelya
        10.08.2017 01:42

        нет, это не так
        Значит я что-то не так понял из статьи (да, я не пробовал GraphQL). Но я и не осуждаю данный подход (как кто-то мог подумать), в своих ситуациях вполне может подходить. Как идея, он мне даже нравится.
        Я про тот случай, когда ко мне приходит фронтендщик, мол, мне нужен такой ендпойнт с такими-то данными (как пример, список постов и для каждого список ВСЕХ комментариев, пример вполне реальный, названия сущностей изменены, но суть та же, лимитирование, пагинация — нет, не слышал). И если у него будет возможность построить самому такой запрос с помощью GraphQL, я не смогу его отговорить, я об этом просто не буду знать. Опять же, если я что-то не так понял, прошу прощения.
        С другой стороны, если уровень бекенд разработчиков недостаточен, чтобы построить более-менее нормальную REST архитектуру (с учётом всех пожеланий), то особой разницы может и не будет. Поэтому, повторюсь, в конечном счёте больше зависит от рук, нежели от технологии.


        1. zelenin
          10.08.2017 02:28

          И если у него будет возможность построить самому такой запрос с помощью GraphQL, я не смогу его отговорить, я об этом просто не буду знать.

          чтобы у фронтендера была такая возможность, вы должны это учесть в схеме и написать ресолверы для постов и комментов.


          При такой схеме комменты вытащить нельзя:


          type Post {
          name: String
          }
          
          type Comment {
          body: String
          }
          
          query GetAllPosts {
          Posts: [Post]
          }

          При такой можно:


          type Post {
          name: String
          comments: [Comment]
          }
          
          type Comment {
          body: String
          }
          
          query GetAllPosts {
          posts: [Post]
          }


          1. sergiobelya
            14.08.2017 23:12

            Спасибо за пояснение.
            Благодаря ему, даже глянул, какие есть библиотеки на php.


  1. abdullam5
    09.08.2017 16:50
    +2

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


    1. sentyaev
      09.08.2017 17:33

      Кстати очень хорошо что так пообсуждали. У меня вот появилось непреодолимое желание запилить какой-нить пэт проджект с использованием GraphQL, а то я тут пишу в стиле «не смотрел но осуждаю».


    1. NikitOS9
      09.08.2017 18:24

      так вперед простой Конкретный пример показать, чтобы появилась эта возможность

      фейсбук как пример не катит


      1. rraderio
        10.08.2017 08:22

        А Github?
        https://developer.github.com/v4/


        1. NikitOS9
          10.08.2017 10:08

          ссылка на доку Introduction to GraphQL…
          разговор же о конкретном примере, где лучше юзать графкул, или все пока только на доки могут ссылаться.


    1. VolCh
      10.08.2017 07:07
      +1

      Как раз на простом особо не вылезут ни недостастки, ни преимущества. Простой API, аналогичный типичному REST-подобному с парой ендпоинтов, покажет небольшие преимущества для фронта и немного увеличившуюся сложность для бэка. А основные преимущества GraphQL лежат, имхо, в приложениях со сложной моделью, а основной недостаток — слаборазвитая экосистема для бэкендов, особенно не в JS+Mongo мире.


      1. arvitaly
        10.08.2017 14:36
        +1

        Думаю, преимущества еще будут сильные в потоковой передаче данных (aka, директивы live, stream, defer и т.д.)
        А в качестве сомнений, наоборот можно отнести запоздалое решение по объединению нескольких запросов в один. С приходом http2 — это скорее минус, чем плюс, выгоднее данные грузить параллельно.
        Самое главное преимущество прямо исходит из названия — графовое представление данных.
        Вообще, все идет по спирали, начинается с примитивов, потом появляются более сложные конфиги, переменные, условия, потом язык конфигураций, а дальше язык программирования.
        Вот и передача данных дошла до этапа сложных, но пока еще декларативных языков, насколько этого хватит, по мне, так уже не хватает, в том же вконтакте, как пример, есть метод execute.

        Кстати, относительно сильных сторон REST, кэширования и проксируемости, тут вся фишка в идентификации ресурсов, а не в этой архитектуре. А если у нас есть идентификаторы, то и для любых других систем это возможно. Еще вопрос, насколько это востребовано, каков реальный процент использования HTTP-прокси-кэша с учетом https.


  1. portey
    10.08.2017 14:28
    +1

    Я как backend-developer скажу, что пишу на graphql проекты уже 2 года, написали свой порт на php — https://github.com/Youshido/GraphQL. Когда у тебя много клиентов, то польза от него просто вау. Хотите узнать в чем идея, читают не данную статью, а посмотрите видео с презентации команды facebook почему они его придумали — коротко и ясно и так сказать в лицо.

    знатакам rest: как потянуты три картинки аватарки в одном запросе?

    {
      me {
        id
        firstName
        lastName
        small: image(width: 100, height: 100, mode: INSET) { // resized directly
          url
        }    
        medium: image(width: 500, height: 300, mode: OUTBOUND) { // different mode
          url
        }    
        fullSize: image {
          url
        }
      }
    }
    


    1. VolCh
      10.08.2017 14:40

      Реально большую работу проделали. Спасибо.


      Долго пытался внедрить ваш порт в свои проекты, но в результате только там, где не требуется работать со сложными БД осталось :( Как вы решаете задачи связи GraphQL с SQL-базами, или, как вариант, Doctrine? Или таких нет в ваших проектах?


    1. rraderio
      10.08.2017 15:10

      видео с презентации команды facebook

      Можно ссылку пожалуйста?


    1. babylon
      14.08.2017 17:12

      portey если вы такие умельцы портируйте на PHP jsonnet ( jsonnet.org ) .GraphQL будет отдыхать. А пока да он весьма неплох.


      1. zelenin
        14.08.2017 19:52

        если вы такие умельцы портируйте на PHP jsonnet ( jsonnet.org ) .GraphQL будет отдыхать. А пока да он весьма неплох.

        но это как бы разные вещи — язык запросов для api и шаблонизатор для json.


  1. rraderio
    11.08.2017 09:52

    Explain GraphQL like I'm five.
    https://dev.to/johnpaulada/explain-graphql-like-im-five


  1. rraderio
    11.08.2017 17:16

    If GraphQL servers are only going to accept pre-approved queries, that defeats the whole point of GraphQL
    https://www.reddit.com/r/reactjs/comments/5aemkc/if_graphql_servers_are_only_going_to_accept/


  1. vintage
    14.08.2017 10:15

    Почему вы сравниваете язык запросов (GraphQL) с архитектурным принципом (REST), а не с другими языками запросов (OData, SparQL, Gremlin, json:api)?


    1. rraderio
      14.08.2017 15:25

      https://jrgql.github.io/ a GraphQL alternative