GraphQL: Sift.js で任意のリスト フィルタリングを有効にする方法。

王林
リリース: 2024-08-05 20:07:20
オリジナル
330 人が閲覧しました

GraphQL: How to Enable Arbitrary List Filtering with Sift.js.

元の記事

GraphQL スキーマにはリスト データ型が存在することがよくあり、一般的な要件は、いくつかの入力変数に基づいてリストをフィルター処理することです。フィルタリングは、ユーザーが必要なデータのみを取得できるようにする重要な機能であり、アプリケーションをより効率的で使いやすくします。

データベースの前にある Prisma など、クエリをサポートする外部データソースを使用する場合、フィルタリングに使用できるライブラリやリソースが多数あります。ただし、GraphQL オブジェクトのリストを返す独自のリゾルバーを作成する場合は、フィルタリング ロジックを抽象化し、スキーマ全体で再利用できるようにすることが有益です。

書籍リストの単純な GraphQL スキーマを考えてみましょう:

type Book {
  title: String
  price: Float
}

type Query {
  books: [Book]
}
ログイン後にコピー

次のリゾルバは、単純なリストから書籍のリストを返します。これは任意のデータ ソースです。

const books = [
  { title: 'The Great Gatsby', price: 10.99 },
  { title: 'To Kill a Mockingbird', price: 12.99 },
  // more books
];

const resolvers = {
  Query: {
    books: () => books,
  },
};
ログイン後にコピー

この例では、ユーザーが次の基準に基づいて書籍をフィルタリングする必要があると仮定します。

  • タイトルの始まり

  • 価格が範囲内にあり、

  • より小さいか大きい。

GraphQL で個別のフィルターとロジックを定義する方法

フィルターを実装する 1 つの方法は、それぞれを個別に定義することです。これには、GraphQL スキーマの入力タイプを変更し、リゾルバー ロジックにフィルターを実装することが含まれます。

スキーマを更新してこれらの新しい入力変数を含めることで、許可されるフィルターとそれらの使用に必要なパラメーターを表現できるようになります。

input BookFilter {
  titleStartsWith: String
  priceLessThan: Float
  priceGreaterThan: Float
}

type Query {
  books(filter: BookFilter): [Book]
}
ログイン後にコピー

更新されたリゾルバーは次のようになります:

const resolvers = {
  Query: {
    books: (_, { filter }) => {
      return books.filter(book => {
        if (filter.titleStartsWith && !book.title.startsWith(filter.titleStartsWith)) {
          return false;
        }
        if (filter.priceLessThan !== undefined && book.price >= filter.priceLessThan) {
          return false;
        }
        if (filter.priceGreaterThan !== undefined && book.price <= filter.priceGreaterThan) {
          return false;
        }
        return true;
      });
    },
  },
};
ログイン後にコピー

この構文でクエリを作成することは、かなり理解しやすいです。 GraphQL リゾルバーにフィルター引数を指定し、必要に応じてこれらのフィルター入力フィールドに値を指定します。

このアプローチの利点

ユーザーに使用を許可するフィルターのみがサポートされます。

これは GraphQL 型検証システムによってサポートされており、許可されている内容以外のフィルタリングは許可されません。バックエンド自体のリゾルバー コードは、許可されていないフィルターさえサポートしません。

このアプローチの欠点

GraphQL スキーマとコードの実装で各フィルターを個別に定義する必要があります。

このコードを異なる GraphQL オブジェクト間で簡単に共有することはできません。ビデオもあり、それらをフィルタリングしたい場合は、ビデオ用の新しいフィルタリング入力タイプが必要になります。 (フィルター入力に一般化することもできますが、その場合、書籍とビデオは異なるものにはなりません。)

新しいフィルターの要件がある場合は、コードを変更して入力フィルター タイプに追加し、それをサポートするようにリゾルバー コードを更新する必要があります。

たとえば、先頭だけでなく任意の場所に部分文字列を含むタイトルをフィルタリングしたい場合、これは新しいフィルタ入力であり、リゾルバの新しい実装です。

Sift クエリ言語をフィルター入力として受け入れることによる任意のフィルター処理

私が見つけた興味深いライブラリ sift を使用すると、MongoDB クエリ構文を使用して、JavaScript で任意のデータのリストを簡単にフィルタリングできます。これは本当に素晴らしいと思いますし、GraphQL で任意のフィルタリングを有効にすることができます。ヘッドレス CMS Strapi は、GraphQL クエリを有効にするためによりカスタム ソリューションに移行する前に、以前は Sift を使用していました!

私がこれに最も興奮したのは、一部の ORM やプロバイダーが GraphQL サービスに組み込んでいる便利な自動フィルタリングをある程度再現する方法のように思えたからです。また、データが特定のデータベースから取得されたものでなくても問題ありません。

上記のスキーマを次のように書き換えることもできます:

input SiftQueryInput {
  field: String
  filter: String
}

type Query {
  books(filter: [SiftQueryInput]): [Book]
}
ログイン後にコピー

そしてリゾルバーは次のことを行います:

const sift = require('sift').default;

const resolvers = {
  Query: {
    books: (_, { filter }) => {
      const siftQuery = filter.reduce((acc, { field, filter }) => {
        acc[field] = JSON.parse(filter);
        return acc;
      }, {});
      return books.filter(sift(siftQuery));
    },
  },
};
ログイン後にコピー

それでは、これはどのように機能するのでしょうか? 「The」で始まるすべての書籍をクエリしたいとします。次のクエリを実行できます:

query {
  books(filter: [{ field: "title", filter: "{\"$regex\": \"^The\"}" }]) {
    title
    price
  }
}
ログイン後にコピー

次の変数を使用します:

{
  "filter": [
    { "field": "title", "filter": "{\"$regex\": \"^The\"}" }
  ]
}
ログイン後にコピー

そして予想どおり、「華麗なるギャツビー」のみにフィルタリングされたリストが返されます!

別の例として、文字「i」を含み、価格が 10 を超える書籍をフィルタリングする場合は、次の変数を指定します。

{
  "filter": [
    { "field": "title", "filter": "{\"$regex\": \"i\"}" },
    { "field": "price", "filter": "{\"$gt\": 10}" }
  ]
}
ログイン後にコピー

そして、『アラバマ物語』という本を取り戻します!

クエリ、スキーマ、リゾルバーでは何も変更する必要がないことに注目してください。他のアプローチでは新しいフィルター入力が必要だったまったく新しいフィルターを、Sift クエリ構文を使用して変数内でのみ表現することができました!

このアプローチの利点

Sift がサポートするフィルタリング ロジックをクエリで表現できるようになりました。別のフィルターに新しい要件が追加された場合でも、新しい入力タイプやリゾルバー ロジックで更新する必要はありません。

同じフィルタリング方法をすべてのタイプで使用できます。 SiftQueryInput のリストを受け入れるだけで、それらの Sift 入力を処理してオブジェクトのリストに適用するバックエンド実装は、リストのタイプによって変わりません。

これにより、オブジェクトの形状が変更されたり、ネストされたりした場合に、オブジェクトを簡単にサポートできます。ドット構文を使用してオブジェクトのネストされたプロパティにアクセスできるため、SiftQueryInput.field は String 型になります。

たとえば、次の Sift クエリを含めることによるフィルタリングが可能です: { field: 'author.name.last', filter: JSON.stringify({ $eq: "Orwell" }) }

欠点と注意点

もちろん、これはエラーが発生しやすい Sift クエリ言語を表現するために文字列を使用しています。そのため、このアプローチを使用するには慎重な検証とエラー処理が必要です。

汎用の SiftQueryInput 型を使用してユーザーのフィルターを収集すると、GraphQL のタイプ セーフが失われます。フィールドが存在すること、またはここでフィルターによって正しい方法で使用されていることを確認する方法がありません。

リストのデータは、フィルタリング リゾルバーが実行される時点で完全に解決される必要があります。まだ解決されていないクエリの下位のフィールドにはアクセスできません。ただし、データが独自のクエリを実行する DB から取得されていない状況では、おそらく JSON ファイルまたは REST API 応答から取得されている可能性があります。

今後の改善点

この場合、GraphQL の安全性が失われるのは残念だと思います。ビルド時に可能な Sift Query オプションを GraphQL スキーマにコンパイルできる可能性があるため、構文は文字列に依存せずに、Sift の実際をより類似して反映します。

結論

結論として、GraphQL で Sift.js を使用すると、任意のフィルタリングを実装する柔軟かつ強力な方法が提供されます。これにより、ソースに関係なく、リスト内のプレーン JavaScript オブジェクトに対して、通常 ORM や特定の GraphQL ベンダー向けに予約されている自動クエリの利点がもたらされます。

あらゆるタイプに適用できる柔軟なクエリ言語を備えた汎用フィルタリング「エンジン」を GraphQL サーバーに提供することで、フィルタリングのロジックが GraphQL クライアントに移されます。これにより、フィルターの反復処理が大幅に高速化され、フィルターでのより高度な表現が可能になります。

GraphQL でのフィルタリングの実装に関するご意見や経験をぜひお聞かせください。以下のコメント欄で共有してください。

以上がGraphQL: Sift.js で任意のリスト フィルタリングを有効にする方法。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!