簡體   English   中英

結合多個 rest 調用以在 apollo-server 中填充 1 個 graphQL 類型的最佳實踐

[英]Best practise to combine multiple rest calls to populate 1 graphQL type in apollo-server

我有 graphql 用戶類型,需要來自多個 REST api 和不同服務器的信息。 基本示例:從 rest 域 1 獲取用戶名,從 rest 域 2 獲取用戶名。兩個 rest 域都有一個共同的“userID”屬性。

我的解析器代碼 atm 的一個簡單示例:

user: async (_source, args, { dataSources }) => {
  try {
    const datasource1 = await dataSources.RESTAPI1.getUser(args.id);
    const datasource2 = await dataSources.RESTAPI2.getUser(args.id);

    return { ...datasource1, ...datasource2 };
  } catch (error) {
    console.log("An error occurred.", error);
  }
  return [];
}

這適用於這個簡單的版本,但我對這個解決方案有兩個問題:首先,IRL 有很多邏輯要合並 2 個 json 結果。 由於某些字段是共享的,但具有不同的數據(或為空)。 所以這就像挑選兩個結果來創建一個組合結果。

我的第二個問題是這仍然是一種瀑布方法。 首先從restapi1獲取數據,完成后調用restapi2。 基本上 apollo-server 正在重新引入 rest-waterfall-fetch graphql 試圖解決。

牢記這兩個問題。我可以優化這段代碼還是重寫是為了更好的性能或可讀性? 或者是否有任何可能有助於這種行為的軟件包?

非常感謝!

關於性能,如果兩個調用相互獨立,您可以利用Promise.all並行執行它們:

const [dataSource1,dataSource2] = await Promise.all([
  dataSources.RESTAPI1.getUser(args.id),
  dataSources.RESTAPI2.getUser(args.id),
])

我們通常讓 GraphQL 的默認解析器邏輯完成繁重的工作,但是如果您發現需要從兩個調用中“挑選”數據,您可以在根解析器中返回類似這樣的內容:

return { dataSource1, dataSource2 }

然后為每個字段編寫解析器:

const resolvers = {
  User: {
    someField: ({ dataSource1, dataSource2 }) => {
      return dataSource1.a || dataSource2.b
    },
    someOtherField: ({ dataSource1, dataSource2 }) => {
      return someCondition ? dataSource1.foo : dataSource2.bar
    },
  }
}

假設您的user解析器返回type User放棄...

type User {
  id: ID!
  datasource1: RandomType
  datasource1: RandomType
}

您可以為type User的每個字段創建單獨的解析器,這可以將user查詢的復雜性降低到僅請求的字段。

query {
 user {
  id
  datasource1 {
    ...
  }
 }
}
const resolvers = {
    Query: {
        user: () => {
            return { id: "..." };
        }
    },
    User: {
        datasource1: () => { ... },
        datasource2: () => { ... } // i wont execute
    }
};

datasource1 & datasource2解析器只會在Query.user執行后並行執行。

用於並行調用。

const users = async (_source, args, { dataSources }) => {
  try {
    const promises = [
      dataSources.RESTAPI1,
      dataSources.RESTAPI2
    ].map(({ getUser }) => getUser(args.id));
    const data = await Promise.all(promises);
    return Object.assign({}, ...data);
  } catch (error) {
    console.log("An error occurred.", error);
  }
  return [];
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM