GraphQL ialah API baharu yang menarik untuk pertanyaan dan operasi ad hoc. Ia sangat fleksibel dan menawarkan banyak faedah. Ia amat sesuai untuk mendedahkan data yang disusun dalam bentuk graf dan pokok. Facebook membangunkan GraphQL pada tahun 2012 dan sumber terbuka pada tahun 2015.
Ia telah berkembang pesat dan menjadi salah satu teknologi terhangat. Banyak syarikat inovatif telah menerima pakai dan menggunakan GraphQL dalam pengeluaran. Dalam tutorial ini anda akan belajar:
GraphQL berada pada tahap terbaik apabila data anda disusun dalam hierarki atau graf dan bahagian hadapan ingin mengakses subset yang berbeza bagi hierarki atau graf tersebut. Pertimbangkan aplikasi yang mendedahkan NBA. Anda mempunyai pasukan, pemain, jurulatih, kejohanan dan banyak maklumat tentang setiap satu. Berikut ialah beberapa contoh pertanyaan:
Saya boleh bertanya ratusan pertanyaan seperti ini. Bayangkan perlu mereka bentuk API yang mendedahkan semua pertanyaan ini ke bahagian hadapan dan dapat dengan mudah memanjangkan API dengan jenis pertanyaan baharu apabila pengguna atau pengurus produk anda menghasilkan kandungan pertanyaan baharu dan menarik.
Ini bukan perkara kecil. GraphQL telah direka untuk menyelesaikan masalah yang tepat ini, dan dengan satu titik akhir API, ia menyediakan fungsi yang luar biasa, seperti yang anda akan lihat tidak lama lagi.
Sebelum kita masuk ke dalam butiran GraphQL, mari kita bandingkan dengan REST, yang kini merupakan jenis API web yang paling popular.
REST mengikut model berorientasikan sumber. Jika sumber kami adalah pemain, jurulatih dan pasukan, kami mungkin mempunyai titik akhir seperti ini:
Biasanya, titik akhir tanpa id hanya mengembalikan senarai id, manakala titik akhir dengan id mengembalikan maklumat lengkap tentang sumber. Sudah tentu, anda boleh mereka bentuk API dengan cara lain (cth. titik akhir /players mungkin juga mengembalikan nama setiap pemain atau semua maklumat tentang setiap pemain).
Masalah dengan pendekatan ini dalam persekitaran dinamik ialah anda sama ada kurang mengambil (cth. anda hanya mendapat id dan memerlukan maklumat lanjut) atau mengambil berlebihan (cth. anda hanya berminat dengan nama).
Ini soalan yang sukar. Apabila tidak mencukupi, jika anda mendapat 100 id, anda perlu membuat 100 panggilan API berasingan untuk mendapatkan maklumat setiap pemain. Apabila anda terlebih ambil, anda membuang banyak masa hujung belakang dan lebar jalur rangkaian menyediakan dan menghantar sejumlah besar data yang anda tidak perlukan.
Terdapat pelbagai cara untuk menyelesaikan masalah ini melalui REHAT. Anda boleh mereka bentuk banyak titik akhir tersuai, setiap satu mengembalikan data yang anda perlukan dengan tepat. Penyelesaian ini tidak berskala. Memastikan API konsisten adalah sukar. Sukar untuk mengembangkannya. Sukar untuk merakam dan menggunakannya. Sukar untuk mengekalkannya apabila terdapat banyak pertindihan antara titik akhir tersuai ini.
Pertimbangkan titik akhir tambahan ini:
Pendekatan lain ialah mengekalkan sebilangan kecil titik akhir biasa tetapi menyediakan sejumlah besar parameter pertanyaan. Penyelesaian ini mengelakkan masalah berbilang titik akhir, tetapi ia melanggar prinsip model REST dan sukar untuk dibangunkan dan diselenggara secara konsisten.
Anda boleh mengatakan bahawa GraphQL telah mengambil pendekatan ini ke hadnya. Ia tidak menganggap sumber yang ditakrifkan secara eksplisit, sebaliknya subgraf keseluruhan domain.
GraphQL memodelkan domain menggunakan sistem jenis yang terdiri daripada jenis dan sifat. Setiap harta ada jenisnya. Jenis sifat boleh menjadi salah satu jenis asas yang disediakan oleh GraphQL, seperti ID, String dan Boolean, atau ia boleh menjadi jenis yang ditentukan pengguna. Nod graf ialah jenis yang ditentukan pengguna, dan tepinya ialah atribut dengan jenis yang ditentukan pengguna.
Sebagai contoh, jika jenis "pemain" mempunyai atribut "pasukan" daripada jenis "pasukan", ini bermakna terdapat kelebihan dari setiap nod pemain ke nod pasukan. Semua jenis ditakrifkan dalam skema yang menerangkan model objek domain GraphQL.
Ini adalah seni bina yang sangat ringkas untuk domain NBA. Pemain itu mempunyai nama, pasukan yang paling banyak dikaitkan dengannya (ya, saya tahu pemain kadangkala berpindah dari satu pasukan ke pasukan lain), dan bilangan kejuaraan yang dimenangi oleh pemain itu.
Pasukan mempunyai nama, senarai nama dan bilangan kejohanan yang dimenangi oleh pasukan.
type Player { id: ID name: String! team: Team! championshipCount: Integer! } type Team { id: ID name: String! players: [Player!]! championshipCount: Integer! }
Terdapat juga pintu masuk yang telah ditetapkan. Mereka bertanya, menukar dan melanggan. Bahagian hadapan berkomunikasi dengan bahagian belakang melalui pintu masuk dan boleh disesuaikan mengikut keperluan.
Ini adalah pertanyaan mudah yang mengembalikan semua pemain:
type Query { allPlayers: [Player!]! }
感叹号表示该值不能为空。对于 allPlayers
查询,它可以返回空列表,但不能返回 null。另外,这意味着列表中不能有空玩家(因为它包含 Player!)。
这是一个基于 Node-Express 的成熟 GraphQL 服务器。它有一个内存中的硬编码数据存储。通常,数据将位于数据库中或从其他服务获取。数据定义如下(如果您最喜欢的球队或球员未能入选,请提前致歉):
let data = { "allPlayers": { "1": { "id": "1", "name": "Stephen Curry", "championshipCount": 2, "teamId": "3" }, "2": { "id": "2", "name": "Michael Jordan", "championshipCount": 6, "teamId": "1" }, "3": { "id": "3", "name": "Scottie Pippen", "championshipCount": 6, "teamId": "1" }, "4": { "id": "4", "name": "Magic Johnson", "championshipCount": 5, "teamId": "2" }, "5": { "id": "5", "name": "Kobe Bryant", "championshipCount": 5, "teamId": "2" }, "6": { "id": "6", "name": "Kevin Durant", "championshipCount": 1, "teamId": "3" } }, "allTeams": { "1": { "id": "1", "name": "Chicago Bulls", "championshipCount": 6, "players": [] }, "2": { "id": "2", "name": "Los Angeles Lakers", "championshipCount": 16, "players": [] }, "3": { "id": "3", "name": "Golden State Warriors", "championshipCount": 5, "players": [] } } }
我使用的库是:
const express = require('express'); const graphqlHTTP = require('express-graphql'); const app = express(); const { buildSchema } = require('graphql'); const _ = require('lodash/core');
这是构建架构的代码。请注意,我向 allPlayers
根查询添加了几个变量。
schema = buildSchema(` type Player { id: ID name: String! championshipCount: Int! team: Team! } type Team { id: ID name: String! championshipCount: Int! players: [Player!]! } type Query { allPlayers(offset: Int = 0, limit: Int = -1): [Player!]! }`
关键部分来了:连接查询并实际提供数据。 rootValue
对象可能包含多个根。
这里,只有 allPlayers
。它从参数中提取偏移量和限制,对所有玩家数据进行切片,然后根据团队 ID 设置每个玩家的团队。这使得每个玩家都是一个嵌套对象。
rootValue = { allPlayers: (args) => { offset = args['offset'] limit = args['limit'] r = _.values(data["allPlayers"]).slice(offset) if (limit > -1) { r = r.slice(0, Math.min(limit, r.length)) } _.forEach(r, (x) => { data.allPlayers[x.id].team = data.allTeams[x.teamId] }) return r }, }
最后,这是 graphql
端点,传递架构和根值对象:
app.use('/graphql', graphqlHTTP({ schema: schema, rootValue: rootValue, graphiql: true })); app.listen(3000); module.exports = app;
将 graphiql
设置为 true
使我们能够使用出色的浏览器内 GraphQL IDE 来测试服务器。我强烈推荐它来尝试不同的查询。
万事俱备。让我们导航到 http://localhost:3000/graphql 并享受一些乐趣。
我们可以从简单的开始,只包含玩家姓名列表:
query justNames { allPlayers { name } } Output: { "data": { "allPlayers": [ { "name": "Stephen Curry" }, { "name": "Michael Jordan" }, { "name": "Scottie Pippen" }, { "name": "Magic Johnson" }, { "name": "Kobe Bryant" }, { "name": "Kevin Durant" } ] } }
好吧。我们这里有一些超级巨星。毫无疑问。让我们尝试一些更奇特的东西:从偏移量 4 开始,有 2 名玩家。对于每个球员,返回他们的名字和他们赢得的冠军数量以及他们的球队名称和球队赢得的冠军数量。
query twoPlayers { allPlayers(offset: 4, limit: 2) { name championshipCount team { name championshipCount } } } Output: { "data": { "allPlayers": [ { "name": "Kobe Bryant", "championshipCount": 5, "team": { "name": "Los Angeles Lakers", "championshipCount": 16 } }, { "name": "Kevin Durant", "championshipCount": 1, "team": { "name": "Golden State Warriors", "championshipCount": 5 } } ] } }
所以科比·布莱恩特随湖人队赢得了 5 个总冠军,湖人队总共获得了 16 个总冠军。凯文·杜兰特在勇士队只赢得了一次总冠军,而勇士队总共赢得了五次总冠军。
魔术师约翰逊无疑是场上的魔术师。但如果没有他的朋友卡里姆·阿卜杜勒·贾巴尔,他不可能做到这一点。让我们将 Kareem 添加到我们的数据库中。我们可以定义 GraphQL 突变来执行从图表中添加、更新和删除数据等操作。
首先,让我们向架构添加突变类型。它看起来有点像函数签名:
type Mutation { createPlayer(name: String, championshipCount: Int, teamId: String): Player }
然后,我们需要实现它并将其添加到根值中。该实现只是获取查询提供的参数并将一个新对象添加到 data['allPlayers']
。它还确保正确设置团队。最后,它返回新的玩家。
createPlayer: (args) => { id = (_.values(data['allPlayers']).length + 1).toString() args['id'] = id args['team'] = data['allTeams'][args['teamId']] data['allPlayers'][id] = args return data['allPlayers'][id] },
要实际添加 Kareem,我们可以调用突变并查询返回的玩家:
mutation addKareem { createPlayer(name: "Kareem Abdul-Jabbar", championshipCount: 6, teamId: "2") { name championshipCount team { name } } } Output: { "data": { "createPlayer": { "name": "Kareem Abdul-Jabbar", "championshipCount": 6, "team": { "name": "Los Angeles Lakers" } } } }
这是一个关于突变的黑暗小秘密......它们实际上与查询完全相同。您可以在查询中修改数据,并且可能只从突变中返回数据。 GraphQL 不会查看您的代码。查询和突变都可以接受参数并返回数据。它更像是语法糖,可以使您的架构更具人类可读性。
订阅是 GraphQL 的另一个杀手级功能。通过订阅,客户端可以订阅每当服务器状态发生变化时就会触发的事件。订阅是后来引入的,不同的框架以不同的方式实现。
GraphQL 将验证针对架构的每个查询或突变。当输入数据具有复杂形状时,这是一个巨大的胜利。您不必编写烦人且脆弱的验证代码。 GraphQL 将为您处理好它。
您可以检查和查询当前架构本身。这为您提供了动态发现架构的元能力。下面是一个返回所有类型名称及其描述的查询:
query q { __schema { types { name description } }
GraphQL 是一项令人兴奋的新 API 技术,与 REST API 相比,它具有许多优势。它背后有一个充满活力的社区,更不用说Facebook了。我预测它将很快成为前端的主要内容。试一试。你会喜欢的。
Atas ialah kandungan terperinci Memahami GraphQL: Pengenalan kepada GraphQL. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!