Дизайн схемы Graphql | Кодементор

логотип.png

Вау, Graphql набрал обороты за последние пару лет. И не без веской причины он позволяет вам выполнять некоторые довольно интересные функции управления данными. А именно, лучшая функция, на мой взгляд, — это возможность запрашивать данные, построчно, а не REST, здесь возьмите весь блок и отфильтруйте то, что вам не нужно. По мере расширения ваших данных REST может стать более обременительным. Тем не менее, Graphql не лишен недостатков, а именно, он написан на своем собственном языке (ура, для изучения совершенно нового языка!), и, опять же, мое мнение, много повторений, мало полезности, которую он обеспечивает для борьбы с этим повторением. Итак, вы вынуждены изучать новый язык, чтобы по-настоящему воспользоваться некоторыми специализированными утилитами (например, graphqli), и вам придется много повторяться. Никаких циклов или массивов, а также никакой структуры «класса», чтобы помочь с возможностью повторного использования. У него есть собственная структура классов, но он полезен только для определения типа похожих полей, а также может быть недостатком в использовании, в зависимости от API, с которым вам придется взаимодействовать для вызова данных из него. С практической точки зрения, graphql отлично выглядит на бумаге, а выполнение в реальном мире может привести к огромным потерям времени и неоптимальным запросам, что в конечном итоге может свести на нет преимущества gql.

А именно, нужно ли вам интегрировать существующие сервисы, которые останутся в живых, с помощью graphql? Ожидайте потратить много времени на настройку запросов в соответствии с операциями CRUD, так как они часто будут давать сбои по разным причинам, а поддержка кросс-среды в настоящее время недостаточно надежна. Много больших успехов, но все еще много головной боли. Вы получите максимальную отдачу от затраченных средств, если у вас есть стек gql, он может быть совершенно новым и автономным или в сочетании с другим очень похожим стеком gql. Смешивание ORM, бэкэндов, фреймов и API действительно может оказать сильное непредвиденное влияние на операции с данными. Давайте рассмотрим некоторые основы проектирования схем, они ни в коем случае не являются исчерпывающими или единственным решением, просто решения общих проблем, с которыми я столкнулся и которые мне приходилось преодолевать с помощью gql.

Вообще говоря, если вам нужно интегрироваться с REST API, многие из них и фреймворк, на котором они построены, не поддерживают настоящие пакетные вызовы. Это важно, если ваш API отправляет одиночные вызовы (даже если он отправляет запрос GET_MANY, если он отправляет каждый запрос по одному, но «пакетно»), старайтесь избегать назначения отношений «многие ко многим» или отношения «один ко многим», вы поблагодаришь меня позже. Итак, в gql:

Shop: {
  id: !ID @unique
    item: String
    location: Location @relation(name: "ShopLocation")
}
//vs
...
  location: [Location!]! @relation//

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

provider(UPDATE, 'Resource', { data: values })
//to
provider(UPDATE, 'Resource', { id: values.id, data: values })

Идентификатор не может быть просто включен. Это также без ссылки. Для подключения ссылок требуется получить идентификатор, а затем показать этот идентификатор по отношению к идентификатору ресурса, к которому вы его подключаете. Обычно получается что-то вроде

provider(UPDATE, 'Resource', { id: values.id, data: { id: values.id, reference: { id: values.reference.id }}})

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

provider(UPDATE, 'Resource', { id: values.id, previousData: values, data: {id: values.id, ...values}})

вернуться к схеме. Может возникнуть соблазн создать типы, объединяющие общие данные, а не повторяющиеся. Здесь соблюдайте осторожность! Опять же, если ваш API не поддерживает пакетные вызовы или если ваш API особенно слаб с глубокими вложенными ссылками или ссылками в целом, ограничьте этот тип группировки типами, которые находятся в самой нижней части пищевой цепи, т. е. типами, которые строятся. блоки и не имеют ссылок вверх и вниз. Например, в магазине это плохая идея, но на уровне отдельного предмета, поскольку он должен ссылаться только на предметы, а другие вещи не должны полагаться на эти ссылки, там все было бы в порядке. . Такие как:

Shop {
  id: ID! @unique
    store: String
    location: Location @relation
    lineItems: LineItem
}
LineItem {
  id: ID! @unique
    quantity: INT
    options: [Option!]! @relation
    items: [Item!]! @relation
}
Option {
  id: ID! @unique
    product: Product @relation(name: 'optionway')
    variant: String
    inStock: Boolean
}
Item {
  id: ID! @unique
    product: Product @relation(name: 'oneway')
    inStock: Boolean
}
Product {
  id: ID! @unique
    sku: String!
    color: String
    features: String
    price: Float!
    ages: String
    warranty: String
}

Поскольку Item и Option являются базовыми единицами и больше не разбиваются на части, использование отношения продукта — это нормально, и вы заметили, что мы минимизируем области one_to_many, используя контейнер lineItem, а не создавая его непосредственно в магазине. Вы можете видеть, хотя, это довольно многословно. Но опять же, если API не поддерживает настоящие пакетные вызовы, это лучше, потому что вы можете передавать 1 запись за раз, чего и ожидает API. Если ваш API имеет очень ограниченную ссылку
поддержки, вы хотели бы включить продукт в элемент и повторить его также в типе опции. Такие мелочи, как эта в вашей схеме, могут сэкономить часы; одиночные запросы или мутации, а также перезапись + поиск ошибок.

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

import querybuilderFactory from 'Provider'
import introspection from 'graphql'
import gql from 'graphql-tag'
import get from 'lodash/get'

const getManyThing = {
Shop: {
['GET_LIST']:  gql`
  fragment shoplist on Shop {
    	id
        store
        location {
        	id
            address
        }
        lineItem {
        	id
            quantity
            option {
            	id
                variant
                product {
                	id
                    sku
                    color
                    warranty
                }
          }
          item {
          	id
            product {
            	id
                sku
                color
                warranty
            }
         }
       }
     }
    `
  }
}

const customQuery = introspection => ({type,resource,param}) => (
  const frag = get(getManyThing, `${resource}.${type}`)
    return buildqueryFactory(introspection, type, resource, param, frag)
)

и это общая идея, включая запросы, которые используют фрагменты, которые являются большим преимуществом перед API, которые борются со ссылками или пакетами, поскольку проанализированный возврат будет в основном доступен с использованием нотации типа «record.shop.lineItem», только с одна область внутри lineItem для работы с двумя массивами, остальные — объекты.

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

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *