Meminta data dari pelayan di sisi klien bukan konsep baru. Ia membolehkan aplikasi memuatkan data tanpa perlu menyegarkan halaman. Ini paling banyak digunakan dalam aplikasi halaman tunggal, yang bukannya mendapatkan halaman yang diberikan dari pelayan, hanya meminta data yang diperlukan untuk menjadikannya di sisi klien.
Pendekatan yang paling biasa di seluruh web dalam beberapa tahun kebelakangan ini adalah gaya seni bina rehat. Walau bagaimanapun, pendekatan ini membawa beberapa batasan untuk aplikasi permintaan data yang tinggi. Dalam sistem yang tenang, kita perlu membuat banyak permintaan HTTP untuk merebut semua data yang kita mahu, yang mempunyai kesan prestasi yang signifikan. Bagaimana jika ada cara untuk meminta pelbagai sumber dalam permintaan HTTP tunggal?
Memperkenalkan GraphQL, bahasa pertanyaan yang menyatukan komunikasi antara klien dan sisi pelayan. Ia membolehkan pihak klien untuk menerangkan dengan tepat data yang diperlukan, dalam satu permintaan.
Dalam artikel ini, kami akan membuat pelayan Node.js/Express dengan laluan GraphQL yang akan mengendalikan semua pertanyaan dan mutasi kami. Kami kemudian akan menguji laluan ini dengan menghantar beberapa permintaan pos dan menganalisis hasil menggunakan Postman.
Anda boleh mencari kod sumber penuh untuk aplikasi ini di sini. Saya juga telah membuat koleksi postman yang boleh anda muat turun di sini.
menyediakan titik akhir graphQL pada pelayan ekspres
<span>// index.js </span><span>require('babel/register'); </span><span>require('./app'); </span>
di app.js kami akan memulakan pelayan kami, berhubung dengan pangkalan data Mongo dan membuat laluan GraphQL.
<span>// app.js </span><span>import express from 'express'; </span><span>import graphqlHTTP from 'express-graphql'; </span><span>import mongoose from 'mongoose'; </span> <span>import schema from './graphql'; </span> <span>var app = express(); </span> <span>// GraphqQL server route </span>app<span>.use('/graphql', graphqlHTTP(req => ({ </span> schema<span>, </span> <span>pretty: true </span><span>}))); </span> <span>// Connect mongo database </span>mongoose<span>.connect('mongodb://localhost/graphql'); </span> <span>// start server </span><span>var server = app.listen(8080, () => { </span> <span>console.log('Listening at port', server.address().port); </span><span>}); </span>
bahagian paling relatif dari kod di atas, dalam konteks artikel ini, adalah di mana kita menentukan laluan GraphQL kami. Kami menggunakan Express-Graphql, middleware ekspres yang dibangunkan oleh pasukan GraphQL Facebook. Ini akan memproses permintaan HTTP melalui GraphQL dan mengembalikan respons JSON. Untuk ini berfungsi, kita perlu melalui pilihan skema GraphQL kami yang dibincangkan di bahagian seterusnya. Kami juga menetapkan pilihan yang cukup untuk benar. Ini menjadikan respons JSON cukup dicetak, menjadikan mereka lebih mudah dibaca.
Untuk GraphQL untuk memahami permintaan kami, kami perlu menentukan skema. Dan skema GraphQL tidak lain daripada sekumpulan pertanyaan dan mutasi. Anda boleh memikirkan pertanyaan sebagai sumber untuk mendapatkan dari pangkalan data dan mutasi sebagai apa -apa jenis kemas kini ke pangkalan data anda. Kami akan mencipta sebagai contoh blogpost dan model Mongoose komen, dan kami kemudian akan membuat beberapa pertanyaan dan mutasi untuknya.
mari kita mulakan dengan membuat model Mongoose. Tidak akan terperinci di sini kerana Mongoose bukan tumpuan artikel ini. Anda boleh menemui dua model dalam model/blog-post.js dan model/komen.js.
Seperti dengan Mongoose, dalam GraphQL kita perlu menentukan struktur data kami. Perbezaannya ialah kita menentukan untuk setiap pertanyaan dan mutasi jenis data yang boleh dimasukkan dan apa yang dihantar dalam respons. Jika jenis ini tidak sepadan, ralat dilemparkan. Walaupun ia kelihatan berlebihan, kerana kami telah menentukan model skema di Mongoose, ia mempunyai kelebihan yang besar, seperti:
Anda boleh mencari kod sumber untuk jenis GraphQL dalam Graphql/Types/. Berikut adalah contoh satu:
<span>// graphql/types/blog-post.js </span><span>import <span>{ </span></span><span> <span>GraphQLObjectType, </span></span><span> <span>GraphQLNonNull, </span></span><span> <span>GraphQLString, </span></span><span> <span>GraphQLID </span></span><span><span>}</span> from 'graphql'; </span> <span>export default new GraphQLObjectType({ </span> <span>name: 'BlogPost', </span> <span>fields: { </span> <span>_id: { </span> <span>type: new GraphQLNonNull(GraphQLID) </span> <span>}, </span> <span>title: { </span> <span>type: GraphQLString </span> <span>}, </span> <span>description: { </span> <span>type: GraphQLString </span> <span>} </span> <span>} </span><span>}); </span>
Di sini, kami mendefinisikan jenis blog Output GraphQL, yang akan kami gunakan lebih lanjut apabila membuat pertanyaan dan mutasi. Perhatikan bagaimana struktur yang serupa dengan Model Model Blogpost. Ia boleh kelihatan pertindihan kerja, tetapi ini adalah kebimbangan yang dipisahkan. Model Mongoose mentakrifkan struktur data untuk pangkalan data, jenis GraphQL mentakrifkan peraturan apa yang diterima dalam pertanyaan atau mutasi ke pelayan anda.
dengan model mongoose dan jenis graphql yang dibuat kini kita boleh membuat skema graphql kami.
<span>// graphql/index.js </span><span>import <span>{ </span></span><span> <span>GraphQLObjectType, </span></span><span> <span>GraphQLSchema </span></span><span><span>}</span> from 'graphql'; </span> <span>import mutations from './mutations'; </span><span>import queries from './queries'; </span> <span>export default new GraphQLSchema({ </span> <span>query: new GraphQLObjectType({ </span> <span>name: 'Query', </span> <span>fields: queries </span> <span>}), </span> <span>mutation: new GraphQLObjectType({ </span> <span>name: 'Mutation', </span> <span>fields: mutations </span> <span>}) </span><span>}); </span>
di sini kami mengeksport graphqlschema di mana kami menentukan dua sifat: pertanyaan dan mutasi. A GraphQLObjectType adalah salah satu daripada banyak jenis GraphQL. Dengan ini, anda boleh menentukan:
Kami mengimport pertanyaan dan mutasi dari lokasi lain, ini hanya untuk tujuan struktur. Kod sumber berstruktur dengan cara yang membolehkan projek kami skala dengan baik jika kami ingin menambah lebih banyak model, pertanyaan, mutasi, dan lain -lain
Pertanyaan dan pembolehubah mutasi yang kita lalui ke medan adalah objek JavaScript biasa. Kekunci adalah nama mutasi atau pertanyaan. Nilai -nilai itu adalah objek JavaScript biasa dengan konfigurasi yang memberitahu GraphQL apa yang perlu dilakukan dengan mereka. Mari ambil pertanyaan GraphQL berikut sebagai contoh:
<span>// index.js </span><span>require('babel/register'); </span><span>require('./app'); </span>
Untuk Grahpql untuk memahami apa yang perlu dilakukan dengan pertanyaan ini, kita perlu menentukan pertanyaan blogpost dan komen. Jadi pemboleh ubah pertanyaan kami akan menjadi seperti ini:
<span>// app.js </span><span>import express from 'express'; </span><span>import graphqlHTTP from 'express-graphql'; </span><span>import mongoose from 'mongoose'; </span> <span>import schema from './graphql'; </span> <span>var app = express(); </span> <span>// GraphqQL server route </span>app<span>.use('/graphql', graphqlHTTP(req => ({ </span> schema<span>, </span> <span>pretty: true </span><span>}))); </span> <span>// Connect mongo database </span>mongoose<span>.connect('mongodb://localhost/graphql'); </span> <span>// start server </span><span>var server = app.listen(8080, () => { </span> <span>console.log('Listening at port', server.address().port); </span><span>}); </span>
sama berlaku untuk mutasi. Ini untuk menjelaskan bahawa terdapat hubungan langsung antara kunci yang kita ada dalam pertanyaan atau mutasi kami dan nama -nama yang kami masukkan dalam pertanyaan. Mari kita lihat bagaimana setiap pertanyaan dan mutasi ini ditakrifkan.
Bermula dari pertanyaan, mari kita ambil dari contoh menggunakan model yang telah kami buat setakat ini. Contoh yang baik adalah untuk mendapatkan catatan blog dan semua komennya.
Dalam penyelesaian REST, anda perlu membuat dua permintaan HTTP untuk ini. Seseorang untuk mendapatkan postingan blog dan yang lain untuk mendapatkan komen, yang akan kelihatan seperti ini:
<span>// graphql/types/blog-post.js </span><span>import <span>{ </span></span><span> <span>GraphQLObjectType, </span></span><span> <span>GraphQLNonNull, </span></span><span> <span>GraphQLString, </span></span><span> <span>GraphQLID </span></span><span><span>}</span> from 'graphql'; </span> <span>export default new GraphQLObjectType({ </span> <span>name: 'BlogPost', </span> <span>fields: { </span> <span>_id: { </span> <span>type: new GraphQLNonNull(GraphQLID) </span> <span>}, </span> <span>title: { </span> <span>type: GraphQLString </span> <span>}, </span> <span>description: { </span> <span>type: GraphQLString </span> <span>} </span> <span>} </span><span>}); </span>
di GraphQL kita boleh membuat ini hanya dalam satu permintaan HTTP, dengan pertanyaan berikut:
<span>// graphql/index.js </span><span>import <span>{ </span></span><span> <span>GraphQLObjectType, </span></span><span> <span>GraphQLSchema </span></span><span><span>}</span> from 'graphql'; </span> <span>import mutations from './mutations'; </span><span>import queries from './queries'; </span> <span>export default new GraphQLSchema({ </span> <span>query: new GraphQLObjectType({ </span> <span>name: 'Query', </span> <span>fields: queries </span> <span>}), </span> <span>mutation: new GraphQLObjectType({ </span> <span>name: 'Mutation', </span> <span>fields: mutations </span> <span>}) </span><span>}); </span>
kita boleh mengambil semua data yang kita mahu dalam satu permintaan tunggal, yang hanya meningkatkan prestasi. Kami juga boleh meminta sifat tepat yang akan kami gunakan. Dalam contoh di atas, respons hanya akan membawa tajuk dan perihalan jawatan blog, dan komen hanya akan membawa teks.
Mengambil hanya medan yang diperlukan dari setiap sumber, boleh memberi impak besar pada masa pemuatan laman web atau aplikasi. Mari kita lihat contoh komen, yang juga mempunyai _id dan sifat postid. Setiap satu daripada ini adalah kecil, 12 bait masing -masing tepat (tidak mengira dengan kekunci objek). Ini mempunyai sedikit kesan apabila ia adalah satu atau beberapa komen. Apabila kita bercakap tentang katakan 200 komen, itu lebih daripada 4800 bait yang tidak akan kita gunakan. Dan itu boleh membuat perbezaan yang signifikan pada masa pemuatan aplikasi. Ini sangat penting untuk peranti dengan sumber yang terhad, seperti yang mudah alih, yang biasanya mempunyai sambungan rangkaian yang lebih perlahan.
Untuk ini berfungsi, kita perlu memberitahu Graphql bagaimana untuk mengambil data untuk setiap pertanyaan tertentu. Mari lihat contoh definisi pertanyaan:
<span>// index.js </span><span>require('babel/register'); </span><span>require('./app'); </span>
Di sini kami membuat pertanyaan yang mengambil satu catatan blog tunggal berdasarkan parameter ID. Ambil perhatian bahawa kami menentukan jenis, yang kami buat sebelum ini, yang mengesahkan output pertanyaan. Kami juga menetapkan objek ARGS dengan argumen yang diperlukan untuk pertanyaan ini. Dan akhirnya, fungsi penyelesaian di mana kita menanyakan pangkalan data dan mengembalikan data.
Untuk mengoptimumkan proses mengambil data dan memanfaatkan ciri unjuran di MongoDB, kami memproses AST yang Graphql menyediakan kami untuk menghasilkan unjuran yang serasi dengan Mongoose. Jadi jika kita membuat pertanyaan berikut:
<span>// app.js </span><span>import express from 'express'; </span><span>import graphqlHTTP from 'express-graphql'; </span><span>import mongoose from 'mongoose'; </span> <span>import schema from './graphql'; </span> <span>var app = express(); </span> <span>// GraphqQL server route </span>app<span>.use('/graphql', graphqlHTTP(req => ({ </span> schema<span>, </span> <span>pretty: true </span><span>}))); </span> <span>// Connect mongo database </span>mongoose<span>.connect('mongodb://localhost/graphql'); </span> <span>// start server </span><span>var server = app.listen(8080, () => { </span> <span>console.log('Listening at port', server.address().port); </span><span>}); </span>
Oleh kerana kita hanya perlu mengambil tajuk dan keterangan dari pangkalan data, fungsi GetProjection akan menghasilkan unjuran sah Mongoose:
<span>// graphql/types/blog-post.js </span><span>import <span>{ </span></span><span> <span>GraphQLObjectType, </span></span><span> <span>GraphQLNonNull, </span></span><span> <span>GraphQLString, </span></span><span> <span>GraphQLID </span></span><span><span>}</span> from 'graphql'; </span> <span>export default new GraphQLObjectType({ </span> <span>name: 'BlogPost', </span> <span>fields: { </span> <span>_id: { </span> <span>type: new GraphQLNonNull(GraphQLID) </span> <span>}, </span> <span>title: { </span> <span>type: GraphQLString </span> <span>}, </span> <span>description: { </span> <span>type: GraphQLString </span> <span>} </span> <span>} </span><span>}); </span>
anda dapat melihat pertanyaan lain di Graphql/Queries/* dalam kod sumber. Kami tidak akan melalui setiap satu kerana semuanya sama dengan contoh di atas.
Mutasi adalah operasi yang akan menangani beberapa jenis perubahan dalam pangkalan data. Seperti pertanyaan kita boleh mengumpulkan mutasi yang berbeza dalam satu permintaan HTTP. Biasanya tindakan terpencil, seperti 'Tambah Komen' atau 'Buat Post Blog'. Walaupun, dengan peningkatan kerumitan aplikasi dan pengumpulan data, untuk analisis, ujian pengalaman pengguna atau operasi kompleks, tindakan pengguna di laman web atau aplikasi boleh mencetuskan sejumlah besar mutasi ke sumber yang berbeza dari pangkalan data anda. Berikutan contoh kami, komen baru di pos blog kami boleh bermakna komen baru dan kemas kini ke blog post komen. Dalam penyelesaian rehat anda akan mempunyai sesuatu seperti berikut:
<span>// graphql/index.js </span><span>import <span>{ </span></span><span> <span>GraphQLObjectType, </span></span><span> <span>GraphQLSchema </span></span><span><span>}</span> from 'graphql'; </span> <span>import mutations from './mutations'; </span><span>import queries from './queries'; </span> <span>export default new GraphQLSchema({ </span> <span>query: new GraphQLObjectType({ </span> <span>name: 'Query', </span> <span>fields: queries </span> <span>}), </span> <span>mutation: new GraphQLObjectType({ </span> <span>name: 'Mutation', </span> <span>fields: mutations </span> <span>}) </span><span>}); </span>
dengan graphql anda boleh melakukannya hanya dalam satu permintaan HTTP dengan sesuatu seperti yang berikut:
query <span>{ </span> blogPosts <span>{ </span> _id<span>, </span> title <span>} </span> comments <span>{ </span> text <span>} </span><span>} </span>
Perhatikan bahawa sintaks untuk pertanyaan dan mutasi adalah sama, hanya mengubah pertanyaan kepada mutasi. Kita boleh meminta data dari mutasi dengan cara yang sama yang kita lakukan dari pertanyaan. Dengan tidak menentukan serpihan, seperti yang kita ada dalam pertanyaan di atas untuk BlogpostCommentInc, kami hanya meminta nilai pulangan yang benar atau palsu, yang sering cukup untuk mengesahkan operasi. Atau kita boleh meminta beberapa data seperti yang kita ada untuk mutasi tambahan, yang boleh berguna untuk mendapatkan data yang dijana pada pelayan sahaja.
mari kita tentukan mutasi kami di pelayan kami. Mutasi dibuat tepat sebagai pertanyaan:
<span>{ </span> <span>blogPosts: {...}, </span> <span>comments: {...} </span><span>} </span>
Mutasi ini akan menambah catatan blog baru dan kembali benar jika berjaya. Perhatikan bagaimana dalam jenis, kami menentukan apa yang akan dikembalikan. Dalam args hujah -hujah yang diterima daripada mutasi. Dan fungsi penyelesaian () sama seperti dalam definisi pertanyaan.
Sekarang kami telah membuat pelayan Express kami dengan laluan GraphQL dan beberapa pertanyaan dan mutasi, mari mengujinya dengan menghantar beberapa permintaan kepadanya.
Terdapat banyak cara untuk menghantar permintaan atau pos ke lokasi, seperti:
Terdapat lebih banyak penyelesaian daripada yang diterangkan di atas. Dua yang pertama adalah yang paling terkenal dan digunakan. GraphIQL adalah penyelesaian pasukan GraphQL untuk memudahkan proses dengan GraphQL, kerana pertanyaan boleh menjadi lebih kompleks untuk ditulis.
Dari ketiga -tiga ini saya akan mengesyorkan GraphIQL, walaupun saya lebih suka dan mengesyorkan di atas semua Postman. Alat ini pastinya merupakan pendahuluan dalam ujian API. Ia menyediakan antara muka intuitif di mana anda boleh membuat dan menyimpan koleksi apa -apa jenis permintaan. Anda juga boleh membuat ujian untuk API anda dan menjalankannya dengan klik butang. Ia juga mempunyai ciri kolaboratif dan membolehkan untuk berkongsi koleksi permintaan. Jadi saya telah mencipta satu yang boleh anda muat turun di sini, yang kemudiannya boleh diimport ke Postman. Jika anda tidak memasang Postman, saya pasti mengesyorkan anda untuk berbuat demikian.
mari kita mulakan dengan menjalankan pelayan. Anda harus mempunyai nod 4 atau lebih tinggi dipasang; Jika anda tidak mempunyai, saya cadangkan menggunakan NVM untuk memasangnya. Kita kemudian boleh menjalankan perkara berikut dalam baris arahan:
<span>// index.js </span><span>require('babel/register'); </span><span>require('./app'); </span>
Pelayan kini bersedia untuk menerima permintaan, jadi mari buat beberapa di Postman. Laluan GraphQL kami ditetapkan pada/Graphql jadi perkara pertama yang perlu dilakukan ialah menetapkan lokasi ke mana kami mahu mengarahkan permintaan kami iaitu http: // localhost: 8080/graphql. Kami kemudian perlu menentukan sama ada ia mendapat atau permintaan pos. Walaupun anda boleh menggunakan salah satu daripada ini, saya lebih suka menyiarkan kerana ia tidak menjejaskan URL, menjadikannya lebih bersih. Kami juga perlu mengkonfigurasi tajuk yang berlaku dengan permintaan, dalam kes kami, kami hanya perlu menambah jenis kandungan yang sama dengan Aplikasi/JSON. Begini bagaimana ia kelihatan semua ditubuhkan di Postman:
Dengan mengandaikan bahawa anda telah mengimport koleksi yang saya telah dibekalkan, anda sepatutnya mempunyai permintaan dan permintaan mutasi yang boleh anda uji. Oleh kerana saya telah menggunakan ID Mongo yang dikodkan keras, jalankan permintaan dalam rangka dan mereka semua berjaya. Menganalisis apa yang saya masukkan ke dalam badan masing -masing dan anda akan melihat ia hanya aplikasi apa yang telah dibincangkan dalam artikel ini. Juga, jika anda menjalankan permintaan pertama lebih dari sekali, kerana ia akan menjadi ID pendua, anda dapat melihat bagaimana kesilapan dikembalikan:
Saya suka mendengar daripada anda: Apa pendapat anda tentang GraphQL dan apa pengalaman anda dengannya?
soalan yang sering ditanya mengenai membuat pelayan graphql dengan node.js dan mongoDB
Terdapat beberapa cara untuk mengoptimumkan pelayan GraphQL untuk prestasi. Salah satu cara ialah menggunakan batching dan caching dengan perpustakaan seperti Dataloader. Ini dapat mengurangkan bilangan permintaan ke pangkalan data MongoDB anda dan meningkatkan masa tindak balas. Cara lain ialah menggunakan pertanyaan berterusan, yang dapat mengurangkan saiz permintaan yang dihantar ke pelayan. Anda juga boleh menggunakan alat pemantauan seperti Apollo Studio untuk mengenal pasti dan memperbaiki kemunculan prestasi. Pertama, anda harus menggunakan HTTPS untuk menyulitkan komunikasi antara klien dan pelayan. Anda juga boleh menggunakan perpustakaan seperti topi keledar untuk menambah tajuk keselamatan ke respons HTTP anda. Untuk pengesahan, anda boleh menggunakan JSON Web Tokens (JWT) dan untuk kebenaran, anda boleh menggunakan perpustakaan seperti GraphQL Shield. Anda juga harus mengesahkan dan membersihkan input pengguna untuk mengelakkan serangan suntikan.
Bagaimana saya boleh memantau pelayan GraphQL saya? Perkhidmatan ini memberikan pandangan tentang prestasi pelayan anda, termasuk masa tindak balas, kadar ralat, dan statistik penggunaan. Mereka juga boleh memberi amaran kepada anda apabila terdapat masalah dengan pelayan anda.
mengendalikan muat naik fail dengan GraphQL boleh dilakukan menggunakan perpustakaan seperti graphql-upload. Perpustakaan ini menyediakan skalar graphqlupload yang boleh anda gunakan dalam skema anda dan fungsi ProcessRequest yang boleh anda gunakan dalam middleware anda untuk memproses fail yang dimuat naik. Langganan dalam GraphQL membolehkan anda menolak kemas kini kepada pelanggan anda secara real-time. Anda boleh menggunakan perpustakaan seperti langganan-pengangkutan-WS untuk mengendalikan sambungan WebSocket untuk langganan. Anda boleh menentukan jenis langganan dalam skema anda dan menggunakan kaedah pubsub.publish dan pubSub.Subscribe untuk menerbitkan dan melanggan peristiwa.
Atas ialah kandungan terperinci Membuat pelayan GraphQL dengan Node.js dan MongoDB. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!