摘要:如下圖嗯,如圖都已經(jīng)查詢(xún)到我們保存的全部數(shù)據(jù),并且全部返回前端了。如圖沒(méi)錯(cuò),什么都沒(méi)有就是查詢(xún)服務(wù)的界面。寫(xiě)好了之后我們?cè)谂渲靡幌侣酚桑M(jìn)入里面,加入下面幾行代碼。
GraphQL一種用為你 API 而生的查詢(xún)語(yǔ)言,2018已經(jīng)到來(lái),PWA還沒(méi)有大量投入生產(chǎn)應(yīng)用之中就已經(jīng)火起來(lái)了,GraphQL的應(yīng)用或許也不會(huì)太遠(yuǎn)了。前端的發(fā)展的最大一個(gè)特點(diǎn)就是變化快,有時(shí)候應(yīng)對(duì)各種需求場(chǎng)景的變化,不得不去對(duì)接口開(kāi)發(fā)很多版本或者修改。各種業(yè)務(wù)依賴(lài)強(qiáng)大的基礎(chǔ)數(shù)據(jù)平臺(tái)快速生長(zhǎng),如何高效地為各種業(yè)務(wù)提供數(shù)據(jù)支持,是所有人關(guān)心的問(wèn)題。而且現(xiàn)在前端的解決方案是將視圖組件化,各個(gè)業(yè)務(wù)線(xiàn)既可以是組件的使用者,也可以是組件的生產(chǎn)者,如果能夠?qū)⑵渲型ㄓ玫膬?nèi)容抽取出來(lái)提供給各個(gè)業(yè)務(wù)方反復(fù)使用,必然能夠節(jié)省寶貴的開(kāi)發(fā)時(shí)間和開(kāi)發(fā)人力。那么問(wèn)題來(lái)了,前端通過(guò)組件實(shí)現(xiàn)了跨業(yè)務(wù)的復(fù)用,后端接口如何相應(yīng)地提高開(kāi)發(fā)效率呢?GraphQL,就是應(yīng)對(duì)復(fù)雜場(chǎng)景的一種新思路。
官方解釋?zhuān)?/p>
GraphQL 既是一種用于 API 的查詢(xún)語(yǔ)言也是一個(gè)滿(mǎn)足你數(shù)據(jù)查詢(xún)的運(yùn)行時(shí)。 GraphQL 對(duì)你的 API 中的數(shù)據(jù)提供了一套易于理解的完整描述,使得客戶(hù)端能夠準(zhǔn)確地獲得它需要的數(shù)據(jù),而且沒(méi)有任何冗余,也讓 API 更容易地隨著時(shí)間推移而演進(jìn),還能用于構(gòu)建強(qiáng)大的開(kāi)發(fā)者工具。
下面介紹一下GraphQL的有哪些好處:
請(qǐng)求你所要的數(shù)據(jù)不多不少
獲取多個(gè)資源只用一個(gè)請(qǐng)求
自定義接口數(shù)據(jù)的字段
強(qiáng)大的開(kāi)發(fā)者工具
API 演進(jìn)無(wú)需劃分版本
本篇文章中將搭配koa實(shí)現(xiàn)一個(gè)GraphQL查詢(xún)的例子,逐步從簡(jiǎn)單kao服務(wù)到mongodb的數(shù)據(jù)插入查詢(xún)?cè)俚紾raphQL的使用,
讓大家快速看到:
搭建koa搭建一個(gè)后臺(tái)項(xiàng)目
后臺(tái)路由簡(jiǎn)單處理方式
利用mongoose簡(jiǎn)單操作mongodb
掌握GraphQL的入門(mén)姿勢(shì)
項(xiàng)目如下圖所示
1、搭建GraphQL工具查詢(xún)界面。
2、前端用jq發(fā)送ajax的使用方式
入門(mén)項(xiàng)目我們都已經(jīng)是預(yù)覽過(guò)了,下面我們動(dòng)手開(kāi)發(fā)吧?。?!
lets do it首先建立一個(gè)項(xiàng)目文件夾,然后在這個(gè)項(xiàng)目文件夾新建一個(gè)server.js(node服務(wù))、config文件夾、mongodb文件夾、router文件夾、controllers文件夾以及public文件夾(這個(gè)主要放前端靜態(tài)數(shù)據(jù)展示頁(yè)面),好啦,項(xiàng)目的結(jié)構(gòu)我們都已經(jīng)建立好,下面在server.js文件夾里寫(xiě)上
server.js
// 引入模塊 import Koa from "koa" import KoaStatic from "koa-static" import Router from "koa-router" import bodyParser from "koa-bodyparser" const app = new Koa() const router = new Router(); // 使用 bodyParser 和 KoaStatic 中間件 app.use(bodyParser()); app.use(KoaStatic(__dirname + "/public")); // 路由設(shè)置test router.get("/test", (ctx, next) => { ctx.body="test page" }); app .use(router.routes()) .use(router.allowedMethods()); app.listen(4000); console.log("graphQL server listen port: " + 4000)
在命令行npm install koa koa-static koa-router koa-bodyparser --save
安裝好上面幾個(gè)模塊,
然后運(yùn)行node server.js,不出什么意外的話(huà),你會(huì)發(fā)現(xiàn)報(bào)如下圖的一個(gè)error
原因是現(xiàn)在的node版本并沒(méi)有支持es6的模塊引入方式。
放心 我們用神器babel-polyfill轉(zhuǎn)譯一下就闊以了。詳細(xì)的請(qǐng)看阮一峰老師的這篇文章
下面在項(xiàng)目文件夾新建一個(gè)start.js,然后在里面寫(xiě)上以下代碼:
start.js
require("babel-core/register")({ "presets": [ "stage-3", ["latest-node", { "target": "current" }] ] }) require("babel-polyfill") require("./server")
然后 在命令行,運(yùn)行npm install babel-core babel-polyfill babel-preset-latest-node babel-preset-stage-3 --save-dev安裝幾個(gè)開(kāi)發(fā)模塊。
安裝完畢之后,在命令行運(yùn)行 node start.js,之后你的node服務(wù)安靜的運(yùn)行起來(lái)了。用koa-router中間件做我們項(xiàng)目路由模塊的管理,后面會(huì)寫(xiě)到router文件夾中統(tǒng)一管理。
打開(kāi)瀏覽器,輸入localhost:4000/test,你就會(huì)發(fā)現(xiàn)訪(fǎng)問(wèn)這個(gè)路由node服務(wù)會(huì)返回test page文字。如下圖
yeah~~kao服務(wù)器基本搭建好之后,下面就是,鏈接mongodb然后把數(shù)據(jù)存儲(chǔ)到mongodb數(shù)據(jù)庫(kù)里面啦。
實(shí)現(xiàn)mongodb的基本數(shù)據(jù)模型tip:這里我們需要mongodb存儲(chǔ)數(shù)據(jù)以及利用mongoose模塊操作mongodb數(shù)據(jù)庫(kù)
在mongodb文件夾新建一個(gè)index.js和 schema文件夾, 在 schema文件夾文件夾下面新建info.js和student.js。
在config文件夾下面建立一個(gè)index.js,這個(gè)文件主要是放一下配置代碼。
又一波文件建立好之后,先在config/index.js下寫(xiě)上鏈接數(shù)據(jù)庫(kù)配置的代碼。
config/index.js
export default { dbPath: "mongodb://localhost/graphql" }
然后在mongodb/index.js下寫(xiě)上鏈接數(shù)據(jù)庫(kù)的代碼。
mongodb/index.js
// 引入mongoose模塊 import mongoose from "mongoose" import config from "../config" // 同步引入 info model和 studen model require("./schema/info") require("./schema/student") // 鏈接mongodb export const database = () => { mongoose.set("debug", true) mongoose.connect(config.dbPath) mongoose.connection.on("disconnected", () => { mongoose.connect(config.dbPath) }) mongoose.connection.on("error", err => { console.error(err) }) mongoose.connection.on("open", async () => { console.log("Connected to MongoDB ", config.dbPath) }) }
上面我們我們代碼還加載了info.js和 studen.js這兩個(gè)分別是學(xué)生的附加信息和基本信息的數(shù)據(jù)模型,為什么會(huì)分成兩個(gè)信息表?原因是順便給大家介紹一下聯(lián)表查詢(xún)的基本方法(嘿嘿~~~)
下面我們分別完成這兩個(gè)數(shù)據(jù)模型
mongodb/schema/info.js
// 引入mongoose import mongoose from "mongoose" // const Schema = mongoose.Schema // 實(shí)例InfoSchema const InfoSchema = new Schema({ hobby: [String], height: String, weight: Number, meta: { createdAt: { type: Date, default: Date.now() }, updatedAt: { type: Date, default: Date.now() } } }) // 在保存數(shù)據(jù)之前跟新日期 InfoSchema.pre("save", function (next) { if (this.isNew) { this.meta.createdAt = this.meta.updatedAt = Date.now() } else { this.meta.updatedAt = Date.now() } next() }) // 建立Info數(shù)據(jù)模型 mongoose.model("Info", InfoSchema)
上面的代碼就是利用mongoose實(shí)現(xiàn)了學(xué)生的附加信息的數(shù)據(jù)模型,用同樣的方法我們實(shí)現(xiàn)了student數(shù)據(jù)模型
mongodb/schema/student.js
import mongoose from "mongoose" const Schema = mongoose.Schema const ObjectId = Schema.Types.ObjectId const StudentSchema = new Schema({ name: String, sex: String, age: Number, info: { type: ObjectId, ref: "Info" }, meta: { createdAt: { type: Date, default: Date.now() }, updatedAt: { type: Date, default: Date.now() } } }) StudentSchema.pre("save", function (next) { if (this.isNew) { this.meta.createdAt = this.meta.updatedAt = Date.now() } else { this.meta.updatedAt = Date.now() } next() }) mongoose.model("Student", StudentSchema)實(shí)現(xiàn)保存數(shù)據(jù)的控制器
數(shù)據(jù)模型都鏈接好之后,我們就添加一些存儲(chǔ)數(shù)據(jù)的方法,這些方法都寫(xiě)在控制器里面。然后在controler里面新建info.js和student.js,這兩個(gè)文件分別對(duì)象,操作info和student數(shù)據(jù)的控制器,分開(kāi)寫(xiě)為了方便模塊化管理。
實(shí)現(xiàn)info數(shù)據(jù)信息的保存,順便把查詢(xún)也先寫(xiě)上去,代碼很簡(jiǎn)單
controlers/info.js
import mongoose from "mongoose" const Info = mongoose.model("Info") // 保存info信息 export const saveInfo = async (ctx, next) => { // 獲取請(qǐng)求的數(shù)據(jù) const opts = ctx.request.body const info = new Info(opts) const saveInfo = await info.save() // 保存數(shù)據(jù) console.log(saveInfo) // 簡(jiǎn)單判斷一下 是否保存成功,然后返回給前端 if (saveInfo) { ctx.body = { success: true, info: saveInfo } } else { ctx.body = { success: false } } } // 獲取所有的info數(shù)據(jù) export const fetchInfo = async (ctx, next) => { const infos = await Info.find({}) // 數(shù)據(jù)查詢(xún) if (infos.length) { ctx.body = { success: true, info: infos } } else { ctx.body = { success: false } } }
上面的代碼,就是前端用post(路由下面一會(huì)在寫(xiě))請(qǐng)求過(guò)來(lái)的數(shù)據(jù),然后保存到mongodb數(shù)據(jù)庫(kù),在返回給前端保存成功與否的狀態(tài)。也簡(jiǎn)單實(shí)現(xiàn)了一下,獲取全部附加信息的的一個(gè)方法。下面我們用同樣的道理實(shí)現(xiàn)studen數(shù)據(jù)的保存以及獲取。
實(shí)現(xiàn)studen數(shù)據(jù)的保存以及獲取
controllers/sdudent.js
import mongoose from "mongoose" const Student = mongoose.model("Student") // 保存學(xué)生數(shù)據(jù)的方法 export const saveStudent = async (ctx, next) => { // 獲取前端請(qǐng)求的數(shù)據(jù) const opts = ctx.request.body const student = new Student(opts) const saveStudent = await student.save() // 保存數(shù)據(jù) if (saveStudent) { ctx.body = { success: true, student: saveStudent } } else { ctx.body = { success: false } } } // 查詢(xún)所有學(xué)生的數(shù)據(jù) export const fetchStudent = async (ctx, next) => { const students = await Student.find({}) if (students.length) { ctx.body = { success: true, student: students } } else { ctx.body = { success: false } } } // 查詢(xún)學(xué)生的數(shù)據(jù)以及附加數(shù)據(jù) export const fetchStudentDetail = async (ctx, next) => { // 利用populate來(lái)查詢(xún)關(guān)聯(lián)info的數(shù)據(jù) const students = await Student.find({}).populate({ path: "info", select: "hobby height weight" }).exec() if (students.length) { ctx.body = { success: true, student: students } } else { ctx.body = { success: false } } }實(shí)現(xiàn)路由,給前端提供API接口
數(shù)據(jù)模型和控制器在上面我們都已經(jīng)是完成了,下面就利用koa-router路由中間件,來(lái)實(shí)現(xiàn)請(qǐng)求的接口。我們回到server.js,在上面添加一些代碼。如下
server.js
import Koa from "koa" import KoaStatic from "koa-static" import Router from "koa-router" import bodyParser from "koa-bodyparser" import {database} from "./mongodb" // 引入mongodb import {saveInfo, fetchInfo} from "./controllers/info" // 引入info controller import {saveStudent, fetchStudent, fetchStudentDetail} from "./controllers/student" // 引入 student controller database() // 鏈接數(shù)據(jù)庫(kù)并且初始化數(shù)據(jù)模型 const app = new Koa() const router = new Router(); app.use(bodyParser()); app.use(KoaStatic(__dirname + "/public")); router.get("/test", (ctx, next) => { ctx.body="test page" }); // 設(shè)置每一個(gè)路由對(duì)應(yīng)的相對(duì)的控制器 router.post("/saveinfo", saveInfo) router.get("/info", fetchInfo) router.post("/savestudent", saveStudent) router.get("/student", fetchStudent) router.get("/studentDetail", fetchStudentDetail) app .use(router.routes()) .use(router.allowedMethods()); app.listen(4000); console.log("graphQL server listen port: " + 4000)
上面的代碼,就是做了,引入mongodb設(shè)置,info以及student控制器,然后鏈接數(shù)據(jù)庫(kù),并且設(shè)置每一個(gè)設(shè)置每一個(gè)路由對(duì)應(yīng)的我們定義的的控制器。
安裝一下mongoose模塊 npm install mongoose --save
然后在命令行運(yùn)行node start,我們服務(wù)器運(yùn)行之后,然后在給info和student添加一些數(shù)據(jù)。這里是通過(guò)postman的谷歌瀏覽器插件來(lái)請(qǐng)求的,如下圖所示
yeah~~~保存成功,繼續(xù)按照步驟多保存幾條,然后按照接口查詢(xún)一下。如下圖
嗯,如圖都已經(jīng)查詢(xún)到我們保存的全部數(shù)據(jù),并且全部返回前端了。不錯(cuò)不錯(cuò)。下面繼續(xù)保存學(xué)生數(shù)據(jù)。
tip: 學(xué)生數(shù)據(jù)保存的時(shí)候關(guān)聯(lián)了信息里面的數(shù)據(jù)哦。所以把id寫(xiě)上去了。
同樣的一波操作,我們多保存學(xué)生幾條信息,然后查詢(xún)學(xué)生信息,如下圖所示。
好了 ,數(shù)據(jù)我們都已經(jīng)保存好了,鋪墊也做了一大把了,下面讓我們真正的進(jìn)入,GrapgQL查詢(xún)的騷操作吧~~~~
重構(gòu)路由,配置GraphQL查詢(xún)界面別忘了,下面我們建立了一個(gè)router文件夾,這個(gè)文件夾就是統(tǒng)一管理我們路由的模塊,分離了路由個(gè)應(yīng)用服務(wù)的模塊。在router文件夾新建一個(gè)index.js。并且改造一下server.js里面的路由全部復(fù)制到router/index.js。
順便在這個(gè)路由文件中加入,graphql-server-koa模塊,這是koa集成的graphql服務(wù)器模塊。graphql server是一個(gè)社區(qū)維護(hù)的開(kāi)源graphql服務(wù)器,可以與所有的node.js http服務(wù)器框架一起工作:express,connect,hapi,koa和restify。可以點(diǎn)擊鏈接查看詳細(xì)知識(shí)點(diǎn)。
加入graphql-server-koa的路由文件代碼如下:
router/index.js
import { graphqlKoa, graphiqlKoa } from "graphql-server-koa" import {saveInfo, fetchInfo} from "../controllers/info" import {saveStudent, fetchStudent, fetchStudentDetail} from "../controllers/student" const router = require("koa-router")() router.post("/saveinfo", saveInfo) .get("/info", fetchInfo) .post("/savestudent", saveStudent) .get("/student", fetchStudent) .get("/studentDetail", fetchStudentDetail) .get("/graphiql", async (ctx, next) => { await graphiqlKoa({endpointURL: "/graphql"})(ctx, next) }) module.exports = router
之后把server.js的路由代碼去掉之后的的代碼如下:
server.js
import Koa from "koa" import KoaStatic from "koa-static" import Router from "koa-router" import bodyParser from "koa-bodyparser" import {database} from "./mongodb" database() const GraphqlRouter = require("./router") const app = new Koa() const router = new Router(); const port = 4000 app.use(bodyParser()); app.use(KoaStatic(__dirname + "/public")); router.use("", GraphqlRouter.routes()) app.use(router.routes()) .use(router.allowedMethods()); app.listen(port); console.log("GraphQL-demo server listen port: " + port)
恩,分離之后簡(jiǎn)潔,明了了很多。然后我們?cè)谥匦聠?dòng)node服務(wù)。在瀏覽器地址欄輸入http://localhost:4000/graphiql,就會(huì)得到下面這個(gè)界面。如圖:
沒(méi)錯(cuò),什么都沒(méi)有 就是GraphQL查詢(xún)服務(wù)的界面。下面我們把這個(gè)GraphQL查詢(xún)服務(wù)完善起來(lái)。
編寫(xiě)GraphQL Schema看一下我們第一張圖,我們需要什么數(shù)據(jù),在GraphQL查詢(xún)界面就編寫(xiě)什么字段,就可以查詢(xún)到了,而后端需要定義好這些數(shù)據(jù)格式。這就需要我們定義好GraphQL Schema。
首先我們?cè)诟夸浶陆ㄒ粋€(gè)graphql文件夾,這個(gè)文件夾用于存放管理graphql相關(guān)的js文件。然后在graphql文件夾新建一個(gè)schema.js。
這里我們用到graphql模塊,這個(gè)模塊就是用javascript參考實(shí)現(xiàn)graphql查詢(xún)。向需要詳細(xì)學(xué)習(xí),請(qǐng)使勁戳鏈接。
我們先寫(xiě)好info的查詢(xún)方法。然后其他都差不多滴。
graphql/schema.js
// 引入GraphQL各種方法類(lèi)型 import { graphql, GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLID, GraphQLList, GraphQLNonNull, isOutputType } from "graphql"; import mongoose from "mongoose" const Info = mongoose.model("Info") // 引入Info模塊 // 定義日期時(shí)間 類(lèi)型 const objType = new GraphQLObjectType({ name: "mete", fields: { createdAt: { type: GraphQLString }, updatedAt: { type: GraphQLString } } }) // 定義Info的數(shù)據(jù)類(lèi)型 let InfoType = new GraphQLObjectType({ name: "Info", fields: { _id: { type: GraphQLID }, height: { type: GraphQLString }, weight: { type: GraphQLString }, hobby: { type: new GraphQLList(GraphQLString) }, meta: { type: objType } } }) // 批量查詢(xún) const infos = { type: new GraphQLList(InfoType), args: {}, resolve (root, params, options) { return Info.find({}).exec() // 數(shù)據(jù)庫(kù)查詢(xún) } } // 根據(jù)id查詢(xún)單條info數(shù)據(jù) const info = { type: InfoType, // 傳進(jìn)來(lái)的參數(shù) args: { id: { name: "id", type: new GraphQLNonNull(GraphQLID) // 參數(shù)不為空 } }, resolve (root, params, options) { return Info.findOne({_id: params.id}).exec() // 查詢(xún)單條數(shù)據(jù) } } // 導(dǎo)出GraphQLSchema模塊 export default new GraphQLSchema({ query: new GraphQLObjectType({ name: "Queries", fields: { infos, info } }) })
看代碼的時(shí)候建議從下往上看~~~~,上面代碼所說(shuō)的就是,建立info和infos的GraphQLSchema,然后定義好數(shù)據(jù)格式,查詢(xún)到數(shù)據(jù),或者根據(jù)參數(shù)查詢(xún)到單條數(shù)據(jù),然后返回出去。
寫(xiě)好了info schema之后 我們?cè)谂渲靡幌侣酚桑M(jìn)入router/index.js里面,加入下面幾行代碼。
router/index.js
import { graphqlKoa, graphiqlKoa } from "graphql-server-koa" import {saveInfo, fetchInfo} from "../controllers/info" import {saveStudent, fetchStudent, fetchStudentDetail} from "../controllers/student" // 引入schema import schema from "../graphql/schema" const router = require("koa-router")() router.post("/saveinfo", saveInfo) .get("/info", fetchInfo) .post("/savestudent", saveStudent) .get("/student", fetchStudent) .get("/studentDetail", fetchStudentDetail) router.post("/graphql", async (ctx, next) => { await graphqlKoa({schema: schema})(ctx, next) // 使用schema }) .get("/graphql", async (ctx, next) => { await graphqlKoa({schema: schema})(ctx, next) // 使用schema }) .get("/graphiql", async (ctx, next) => { await graphiqlKoa({endpointURL: "/graphql"})(ctx, next) // 重定向到graphiql路由 }) module.exports = router
詳細(xì)請(qǐng)看注釋?zhuān)缓蟊煌洶惭b好npm install graphql-server-koa graphql --save這兩個(gè)模塊。安裝完畢之后,重新運(yùn)行服務(wù)器的node start(你可以使用nodemon來(lái)啟動(dòng)本地node服務(wù),免得來(lái)回啟動(dòng)。)
然后刷新http://localhost:4000/graphiql,你會(huì)發(fā)現(xiàn)右邊會(huì)有查詢(xún)文檔,在左邊寫(xiě)上查詢(xún)方式,如下圖
重整Graphql代碼結(jié)構(gòu),完成所有數(shù)據(jù)查詢(xún)現(xiàn)在是我們把schema和type都寫(xiě)到一個(gè)文件上面了去了,如果數(shù)據(jù)多了,字段多了變得特別不好維護(hù)以及review,所以我們就把定義type的和schema分離開(kāi)來(lái),說(shuō)做就做。
在graphql文件夾新建info.js,studen.js,文件,先把info type 寫(xiě)到info.js代碼如下
graphql/info.js
import { graphql, GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLID, GraphQLList, GraphQLNonNull, isOutputType } from "graphql"; import mongoose from "mongoose" const Info = mongoose.model("Info") const objType = new GraphQLObjectType({ name: "mete", fields: { createdAt: { type: GraphQLString }, updatedAt: { type: GraphQLString } } }) export let InfoType = new GraphQLObjectType({ name: "Info", fields: { _id: { type: GraphQLID }, height: { type: GraphQLString }, weight: { type: GraphQLString }, hobby: { type: new GraphQLList(GraphQLString) }, meta: { type: objType } } }) export const infos = { type: new GraphQLList(InfoType), args: {}, resolve (root, params, options) { return Info.find({}).exec() } } export const info = { type: InfoType, args: { id: { name: "id", type: new GraphQLNonNull(GraphQLID) } }, resolve (root, params, options) { return Info.findOne({ _id: params.id }).exec() } }
分離好info type 之后,一鼓作氣,我們順便把studen type 也完成一下,代碼如下,原理跟info type 都是相通的,
graphql/student.js
import { graphql, GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLID, GraphQLList, GraphQLNonNull, isOutputType, GraphQLInt } from "graphql"; import mongoose from "mongoose" import {InfoType} from "./info" const Student = mongoose.model("Student") let StudentType = new GraphQLObjectType({ name: "Student", fields: { _id: { type: GraphQLID }, name: { type: GraphQLString }, sex: { type: GraphQLString }, age: { type: GraphQLInt }, info: { type: InfoType } } }) export const student = { type: new GraphQLList(StudentType), args: {}, resolve (root, params, options) { return Student.find({}).populate({ path: "info", select: "hobby height weight" }).exec() } }
tips: 上面因?yàn)橛辛寺?lián)表查詢(xún),所以引用了info.js
然后調(diào)整一下schema.js的代碼,如下:
import { GraphQLSchema, GraphQLObjectType } from "graphql"; // 引入 type import {info, infos} from "./info" import {student} from "./student" // 建立 schema export default new GraphQLSchema({ query: new GraphQLObjectType({ name: "Queries", fields: { infos, info, student } }) })
看到代碼是如此的清新脫俗,是不是深感欣慰。好了,graophql數(shù)據(jù)查詢(xún)都已經(jīng)是大概比較完善了。
課程的數(shù)據(jù)大家可以自己寫(xiě)一下,或者直接到我的github項(xiàng)目里面copy過(guò)來(lái)我就不一一重復(fù)的說(shuō)了。
下面寫(xiě)一下前端接口是怎么查詢(xún)的,然后讓數(shù)據(jù)返回瀏覽器展示到頁(yè)面的。
前端接口調(diào)用在public文件夾下面新建一個(gè)index.html,js文件夾,css文件夾,然后在js文件夾建立一個(gè)index.js, 在css文件夾建立一個(gè)index.css,代碼如下
public/index.html
GraphQL-demo GraphQL-前端demo
課程列表
- 暫無(wú)數(shù)據(jù)....
班級(jí)學(xué)生列表
- 暫無(wú)數(shù)據(jù)....
點(diǎn)擊常規(guī)獲取課程列表點(diǎn)擊常規(guī)獲取班級(jí)學(xué)生列表點(diǎn)擊graphQL一次獲取所有數(shù)據(jù),問(wèn)你怕不怕?
我們主要看js請(qǐng)求方式 代碼如下
window.onload = function () { $("#btn2").click(function() { $.ajax({ url: "/student", data: {}, success:function (res){ if (res.success) { renderStudent (res.data) } } }) }) $("#btn1").click(function() { $.ajax({ url: "/course", data: {}, success:function (res){ if (res.success) { renderCourse(res.data) } } }) }) function renderStudent (data) { var str = "" data.forEach(function(item) { str += "
css的代碼 我就不貼出來(lái)啦。大家可以去項(xiàng)目直接拿嘛。
所有東西都已經(jīng)完成之后,重新啟動(dòng)node服務(wù),然后訪(fǎng)問(wèn),http://localhost:4000/就會(huì)看到如下界面。界面丑,沒(méi)什么設(shè)計(jì)美化細(xì)胞,求輕噴~~~~
操作點(diǎn)擊之后就會(huì)想第二張圖一樣了。
所有效果都出來(lái)了,本篇文章也就到此結(jié)束了。
附上項(xiàng)目地址: https://github.com/naihe138/GraphQL-demo
ps:喜歡的話(huà)丟一個(gè)小星星(star)給我嘛
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/90692.html
摘要:要對(duì)進(jìn)行黑盒測(cè)試測(cè)試的最好辦法是對(duì)他們進(jìn)行黑盒測(cè)試,黑盒測(cè)試是一種不關(guān)心應(yīng)用內(nèi)部結(jié)構(gòu)和工作原理的測(cè)試方法,測(cè)試時(shí)系統(tǒng)任何部分都不應(yīng)該被。此外,有了黑盒測(cè)試并不意味著不需要單元測(cè)試,針對(duì)的單元測(cè)試還是需要編寫(xiě)的。 本文首發(fā)于之乎專(zhuān)欄前端周刊,全文共 6953 字,讀完需 8 分鐘,速度需 2 分鐘。翻譯自:RingStack 的文章 https://blog.risingstack.co...
摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥(niǎo)雀呼晴,侵曉窺檐語(yǔ)。葉上初陽(yáng)乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門(mén),久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...
摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥(niǎo)雀呼晴,侵曉窺檐語(yǔ)。葉上初陽(yáng)乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門(mén),久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...
閱讀 3589·2021-09-22 10:52
閱讀 1600·2021-09-09 09:34
閱讀 2001·2021-09-09 09:33
閱讀 768·2019-08-30 15:54
閱讀 2687·2019-08-29 11:15
閱讀 726·2019-08-26 13:37
閱讀 1680·2019-08-26 12:11
閱讀 2987·2019-08-26 12:00