Разрешить один и тот же объект из двух несвязных источников в GraphQL - PullRequest
0 голосов
/ 18 июня 2019

У меня проблема, я не знаю, как ее решить.

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

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

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

Пример:

API A 

type User {
   id: string,
   communication: Communication
}

type Communication {
   mail: string,
}
API B

type User {
   id: string,
   mail: string,
}

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

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

1 Ответ

1 голос
/ 18 июня 2019

Вам необходимо решить, какая «форма» типа User имеет смысл для вашего клиентского приложения, независимо от того, что возвращается API REST.Для этого примера, скажем, мы используем:

type User {
  id: String
  mail: String
}

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

type Query {
  getUser: User
}

Если предположить, что я не знаю, какой API запрашивать у пользователя, наш распознаватель для getUser может выглядеть примерно так:

async () => {
  const [userFromA, userFromB] = await Promise.all([
    fetchUserFromA(),
    fetchUserFromB(),
  ])

  // transform response
  if (userFromA) {
    const { id, communication: { mail } } = userFromA
    return {
      id,
      mail,
    }
  }

  // response from B is already in the correct "shape", so just return it
  if (userFromB) {
    return userFromB
  }
}

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

const resolvers = {
  Query: {
    getUser: async () => {
      const [userFromA, userFromB] = await Promise.all([
        fetchUserFromA(),
        fetchUserFromB(),
      ])
      return userFromA || userFromB
    },
  },
  User: {
    mail: (user) => {
      if (user.communication) {
        return user.communication.mail
      }
      return user.mail
    }
  }, 
}

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

type User {
  id: String
  details: UserDetails
}

type UserDetails {
  email: String
}

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

...