web-dev-qa-db-ja.com

GraphQLとApolloStackを使用して共用体/インターフェースフィールドを解決する方法

GraphQLインスタンスとのインターフェースを利用していますが、この質問はおそらくユニオンにも当てはまります。インターフェイスを実装するすべてのタイプに共通のフィールドが2つありますが、各タイプには複数の追加フィールドがあります。

次のスキーマが与えられた

interface FoodType {
  id: String
  type: String
}

type Pizza implements FoodType {
  id: String
  type: String
  pizzaType: String
  toppings: [String]
  size: String
}

type Salad implements FoodType {
  id: String
  type: String
  vegetarian: Boolean
  dressing: Boolean
}

type BasicFood implements FoodType {
  id: String
  type: String
}

および次のリゾルバ

{
  Query: {
    GetAllFood(root) {
      return fetchFromAllFoodsEndpoint()
        .then((items) => {
          return mergeExtraFieldsByType(items);
        });
    },
  },
  FoodType: {
    __resolveType(food) {
      switch (food.type) {
        case 'pizza': return 'Pizza';
        case 'salad': return 'Salad';
        default: return 'BasicFood';
      }
    },
  },
  Pizza: {
    toppings({pizzaType}) {
      return fetchFromPizzaEndpoint(pizzaType);
    }
  }
}

タイプごとに追加のフィールドを取得するにはどうすればよいですか?

現在、allFoodidの基本フィールドを取得するために、すべての食品を取得するtypeがあります。この後、結果をループし、タイプPizzaが見つかった場合は、fetchFromPizzaEndpointを呼び出して、追加のフィールドを取得し、それらを元の基本タイプにマージします。タイプごとにこれを繰り返します。

上記のように、Pizza.toppingsなどのタイプの特定のフィールドを手動で解決することもできます。

今の私の解決策は理想的ではありません。単一のフィールドtoppingsで行うのとほぼ同じ方法で、タイプごとに複数のフィールドを解決できるようにしたいと思います。これはGraphQLで可能ですか?これは非常に一般的なユースケースであるため、これを実現するためのより良い方法が必要です。

理想的には、リゾルバーでクエリが要求しているフラグメントを知りたいので、要求されたエンドポイント(フラグメントごとに1つのエンドポイント)のみを呼び出すことができます。

{
  Query: {
    GetAllFood(root) {
      return fetchFromAllFoodsEndpoint();
    },
  },
  FoodType: {
    __resolveType(food) {
      switch (food.type) {
        case 'pizza': return 'Pizza';
        case 'salad': return 'Salad';
        default: return 'BasicFood';
      }
    },
  },
  Pizza: {
    __resolveMissingFields(food) {
      return fetchFromPizzaEndpoint(food.id);
    }
  },
  Salad: {
    __resolveMissingFields(food) {
      return fetchFromSaladEndpoint(food.id);
    }
  }
}
10
JustinN

この質問は5か月前のものですが、この問題を抱えている他の人の助けになることを願っています。彼は次のような構造のリゾルバを渡します

{
    Query: {
        GetAllFood(root) {
        return fetchFromAllFoodsEndpoint()
            .then((items) => {
            return mergeExtraFieldsByType(items);
            });
        },
    },
    FoodType: {
        __resolveType(food) {
        switch (food.type) {
            case 'pizza': return 'Pizza';
            case 'salad': return 'Salad';
            default: return 'BasicFood';
        }
        },
    },
    Pizza: {
        toppings({pizzaType}) {
        return fetchFromPizzaEndpoint(pizzaType);
        }
    }
}

しかし、彼は本当に次のようなものを望んでいました(正確ではありませんが、クエリに対する__resolveTypeの場所を強調しています)

{
    Query: {
        GetAllFood(root) {
        return fetchFromAllFoodsEndpoint()
            .then((items) => {
            return mergeExtraFieldsByType(items);
            });
        },
    },
    FoodType: {
        __resolveType(data, ctx, info) {
            return whatIsTheType(data, ctx, info)
        }
    }
}

公式ドキュメントには例があります ここ 、しかしそれは私が混乱していると思ったインターフェースタイプだけを含んでいます。利用可能なUnionタイプ(インターフェースと同じように構成されている)の追加の完全な実行可能な例があります ここ

11
Sean Ryan