Как мой распознаватель Apollo GraphQL «смотрит в будущее», не теряя преимущества традиционной структуры распознавателя? - PullRequest
1 голос
/ 11 апреля 2020

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

В частности, нижняя часть этого дерева несколько динамична c и не ограничена. В общем, это выглядит как эта упрощенная схема:

type Query {
  outer: OuterWrapper!
}

type OuterWrapper {
  inner: InnerWrapper!
}

type InnerWrapper {
  recurse(name: String = ""): RecursiveType!
}

type RecursiveType {
  recurse(name: String = ""): [RecursiveType!]!
  name: String!
}

В настоящее время у нас есть только один распознаватель Apollo в верхней части дерева (outer), и мы используем graphql-fields библиотека для обработки параметра info. По сути, мы «смотрим в будущее» для детей - популярный шаблон до , оптимизирующий внутренних запросов.

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

Однако у него есть два ограничения. :

  1. Ответ graphql-fields не содержит значений параметров по умолчанию. Если бы я написал правильный распознаватель recurse, Apollo передал бы значение схемы по умолчанию для name, если его не было в запросе. Я нашел альтернативную библиотеку (graphql-parse-resolve-info), на которую я собираюсь перейти, но это не решение Apollo, и ...
  2. Если мы выбрасываем ошибку, путь отражает то, что это произошло в распознавателе outer, а не дальше по дереву, где это будет более точным и полезным для пользователя.

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

Есть ли способ, которым я мог бы постепенно построить свой сингл? внутренний запрос REST с использованием традиционной / полностью определенной структуры резолвера?

Я мог бы представить, что резолверы создают запрос и сохраняют его в context - резолвер outer создаст запрос, и последующие решатели изменили бы это, как они считают нужным. Затем каждый распознаватель может вернуть обещание, ожидающее ответа REST. Однако я не вижу хорошего способа узнать, когда все мои распознаватели были вызваны (и внесли свои изменения), и, таким образом, запустить запрос REST в бэкэнд, или чтобы каждый распознаватель знал, где он находится в структуре запроса. (и, следовательно, где искать данные в ответе REST).

Есть ли другой подход, который я не рассматривал?

1 Ответ

1 голос
/ 11 апреля 2020

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

Если у вас было несколько обращений к источнику данных, возможно, имеет смысл разделить их по разным распознавателям. Если вам нужно всего лишь один раз обратиться к источнику данных, лучше всего это сделать на верхнем уровне и использовать «lookahead». graphql-parse-resolve-info - отличная библиотека, которая может помочь с этим.

Единственное улучшение по сравнению с тем, что вы делаете сейчас, может заключаться в перемещении большей части логики c для преобразования ответа REST в средства распознавания для некоторых из ваши не root поля. Таким образом, вы можете постепенно преобразовывать значение parent, передаваемое каждому распознавателю, по мере выполнения выполнения на каждом «уровне» вашего запроса.

...