Artikel Asal
Selalunya, terdapat jenis data senarai dalam skema GraphQL anda dan keperluan biasa ialah menapis senarai berdasarkan beberapa pembolehubah input. Penapisan ialah ciri penting yang membolehkan pengguna mendapatkan semula data yang mereka perlukan sahaja, menjadikan aplikasi lebih cekap dan mesra pengguna.
Terdapat banyak perpustakaan dan sumber tersedia untuk penapisan apabila menggunakan sumber data luaran yang menyokong pertanyaan, seperti Prisma di hadapan pangkalan data. Walau bagaimanapun, apabila menulis penyelesai anda sendiri yang mengembalikan senarai objek GraphQL, adalah berfaedah untuk mengabstrak logik penapisan dan menjadikannya boleh digunakan semula merentas skema anda.
Mari kita pertimbangkan skema GraphQL yang mudah untuk senarai buku:
type Book { title: String price: Float } type Query { books: [Book] }
Dan penyelesai berikut yang mengembalikan senarai buku daripada senarai ringkas. Ini boleh jadi mana-mana sumber data.
const books = [ { title: 'The Great Gatsby', price: 10.99 }, { title: 'To Kill a Mockingbird', price: 12.99 }, // more books ]; const resolvers = { Query: { books: () => books, }, };
Untuk contoh kita, mari kita anggap pengguna perlu menapis buku berdasarkan kriteria berikut:
Bermula dengan tajuk apa
Harga berada dalam julat, kurang daripada dan lebih besar daripada
Satu cara untuk melaksanakan penapis adalah dengan mentakrifkan setiap satu secara individu. Ini melibatkan membuat perubahan pada jenis input skema GraphQL dan melaksanakan penapis dalam logik penyelesai.
Anda boleh mengemas kini skema anda untuk memasukkan pembolehubah input baharu ini, membolehkan anda menyatakan penapis yang dibenarkan dan parameter yang diperlukan untuk menggunakannya:
input BookFilter { titleStartsWith: String priceLessThan: Float priceGreaterThan: Float } type Query { books(filter: BookFilter): [Book] }
Penyelesai yang dikemas kini mungkin kelihatan seperti ini:
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; }); }, }, };
Membuat pertanyaan dengan sintaks ini agak mudah difahami. Anda akan membekalkan hujah penapis kepada penyelesai GraphQL, memberikan nilai untuk medan input penapis tersebut jika diperlukan.
Hanya penapis yang anda mahu benarkan pengguna gunakan disokong.
Ini disokong oleh sistem pengesahan jenis GraphQL, yang tidak akan membenarkan penapisan di luar apa yang dibenarkan. Kod penyelesai di bahagian belakang itu sendiri tidak menyokong penapis yang tidak dibenarkan.
Anda perlu menentukan setiap penapis secara individu dalam skema GraphQL dan dalam pelaksanaan dalam kod.
Anda tidak boleh berkongsi kod ini dengan mudah antara objek GraphQL yang berbeza. Jika anda juga mempunyai Video dan ingin menapisnya, ia memerlukan jenis input penapisan baharu untuk video. (Anda boleh membuat generalisasi kepada input penapis, tetapi kemudian Buku dan Video tidak boleh berbeza.)
Jika terdapat keperluan untuk penapis baharu, ia memerlukan perubahan kod untuk ditambahkan pada jenis penapis input dan untuk mengemas kini kod penyelesai untuk menyokongnya.
Cth., jika anda ingin menapis tajuk yang menyertakan subrentetan di mana-mana sahaja, bukan sahaja pada permulaan, ini ialah input penapis baharu dan pelaksanaan baharu dalam penyelesai anda.
Pustaka menarik yang saya temui, menapis, membenarkan penggunaan sintaks pertanyaan MongoDB untuk menapis senarai data sewenang-wenang dengan mudah dalam JavaScript. Saya rasa ini sangat bagus dan boleh mendayakan penapisan sewenang-wenang dalam GraphQL. CMS Strapi tanpa kepala sebelum ini menggunakan Sift sebelum beralih kepada penyelesaian yang lebih tersuai untuk membolehkan pertanyaan GraphQL mereka!
Saya amat teruja dengan perkara ini kerana ia nampaknya merupakan satu cara untuk menghasilkan semula penapisan automatik berguna yang telah dibina oleh sesetengah ORM dan penyedia dalam perkhidmatan GraphQL mereka. Dan tidak mengapa jika data itu tidak datang dari pangkalan data tertentu.
Anda boleh menulis semula skema di atas kepada yang berikut:
input SiftQueryInput { field: String filter: String } type Query { books(filter: [SiftQueryInput]): [Book] }
Dan penyelesai kepada:
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)); }, }, };
Jadi bagaimana ini berfungsi? Katakan anda ingin menanyakan semua buku yang bermula dengan 'The'. Anda boleh melaksanakan pertanyaan ini:
query { books(filter: [{ field: "title", filter: "{\"$regex\": \"^The\"}" }]) { title price } }
Dengan pembolehubah ini:
{ "filter": [ { "field": "title", "filter": "{\"$regex\": \"^The\"}" } ] }
Dan seperti yang dijangkakan, anda akan mendapatkan kembali senarai yang ditapis kepada 'The Great Gatsby'!
Contoh lain, jika anda ingin menapis buku yang mengandungi huruf 'i' dan harganya lebih besar daripada 10, anda akan membekalkan pembolehubah berikut:
{ "filter": [ { "field": "title", "filter": "{\"$regex\": \"i\"}" }, { "field": "price", "filter": "{\"$gt\": 10}" } ] }
Dan anda mendapat kembali buku 'To Kill a Mockingbird'!
Perhatikan bahawa kami tidak perlu mengubah apa-apa dalam pertanyaan, skema atau penyelesai! Kami dapat menyatakan penapis baharu sepenuhnya yang memerlukan input penapis baharu dalam pendekatan lain, hanya dalam pembolehubah menggunakan sintaks pertanyaan Ayak!
Sebarang logik penapisan yang disokong Sift kini boleh dinyatakan dalam pertanyaan anda. Jika keperluan baharu masuk untuk penapis yang berbeza, ia tidak memerlukan pengemaskinian dengan jenis input baharu dan logik penyelesai.
Kaedah penapisan yang sama boleh digunakan merentas semua jenis anda! Hanya menerima senarai SiftQueryInputs dan pelaksanaan bahagian belakang untuk mengendalikan input Ayak tersebut dan menerapkannya pada senarai objek tidak berubah mengikut jenis senarai itu.
Ini menyokong objek dengan mudah jika bentuknya berubah atau menjadi bersarang. Medan SiftQueryInput. adalah jenis String kerana anda boleh mengakses sifat bersarang pada objek dengan sintaks titik.
Cth., menapis dengan memasukkan pertanyaan Ayak ini mungkin: { medan: 'author.name.last', penapis: JSON.stringify({ $eq: "Orwell" }) }
Sudah tentu, ini menggunakan rentetan untuk menyatakan bahasa pertanyaan Ayak, yang terdedah kepada ralat—jadi pengesahan yang teliti dan pengendalian ralat diperlukan untuk menggunakan pendekatan ini.
Dengan menggunakan jenis SiftQueryInput generik untuk mengumpulkan penapis pengguna, anda kehilangan jenis keselamatan GraphQL—ia tidak mempunyai cara untuk mengesahkan bahawa medan itu wujud atau sedang digunakan dengan cara yang betul di sini oleh penapis anda.
Data senarai perlu diselesaikan sepenuhnya pada titik penyelesai penapisan dijalankan. Ia tidak boleh mengakses medan lebih jauh ke bawah pertanyaan yang masih belum diselesaikan. Tetapi untuk situasi di mana data tidak datang daripada DB dengan pertanyaannya sendiri, mungkin daripada fail JSON atau respons API REST, ini mungkin juga.
Saya rasa kehilangan keselamatan GraphQL adalah memalukan dalam kes ini. Anda mungkin boleh menyusun pilihan Sift Query ke dalam skema GraphQL pada masa binaan, jadi sintaks mencerminkan keadaan sebenar Sift dengan lebih serupa, tanpa bergantung pada rentetan.
Kesimpulannya, menggunakan Sift.js dalam GraphQL menyediakan cara yang fleksibel dan berkuasa untuk melaksanakan penapisan sewenang-wenangnya. Ia membawa faedah pertanyaan automatik yang biasanya dikhaskan untuk ORM dan vendor GraphQL tertentu kepada objek JavaScript biasa dalam senarai, tanpa mengira sumbernya.
Dengan menyediakan 'enjin' penapisan generik dalam pelayan GraphQL, dengan bahasa pertanyaan fleksibel yang boleh digunakan untuk sebarang jenis, logik penapisan dialihkan kepada klien GraphQL. Ini membolehkan lelaran yang lebih pantas pada penapis dan membolehkan tahap ekspresi yang lebih besar dalam penapis.
Saya ingin mendengar pendapat dan pengalaman anda dengan melaksanakan penapisan dalam GraphQL—kongsinya dalam ulasan di bawah!
Atas ialah kandungan terperinci GraphQL: Cara Mendayakan Penapisan Senarai Arbitrari dengan Sift.js.. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!