系列文章:
<a href="https://segmentfault.com/a/1190000006132986">graphql 核心概念</a>
graphql-js 淺嘗(本文)
常言道,實踐是檢驗真理的唯一标準。
上一篇文章講了 graphql 的核心概念,所提到的一些例子都是理論化的,并沒有實際代碼做支撐,就好像在畫一個大餅,總是讓人不那麼信服。
它真的有那麼神奇嗎?那就同我一起看下去,用事實說話。
之前那篇文章一直有提到 graphql 是一個概念,每個語言可以有自己實作它的方式。因為,我是搞前端的,對 javascript 比較熟悉,是以,這裡就用 graphql-js(graphql 的 javascript 實作)來舉例。
hello world
遵循傳統,第一個例子必須是 hello world。
首先,安裝就不用多說了。
npm install graphql-js --save
那這個例子該怎麼設計哪?假設,查詢一個 hello 字元串,就傳回一個 world 字元串,很明顯 type 的結構就該是這樣
type helloworld {
hello: string
}
如何實作這個 helloworld 類型哪?graphql-js 已經定義好了基礎類,我們直接調用就行。那麼,這個 type 實作起來也就非常簡單了
import {
graphqlstring,
graphqlobjecttype,
} from 'graphql';
const helloworldtype = new graphqlobjecttype({
name: 'helloworldtype',
fields: () => ({
hello: {
type: graphqlstring,
}
})
});
簡單分析一下上面的代碼,可以看到 helloworldtype 是一個 graphqlobjecttype 的執行個體,它包含一個 fields 是 hello,這個 hello 所對應的傳回類型是字元串。
那如何傳回 world 字元串?那就給它個 resolve 方法
resolve() {
return 'world';
},
這樣類型就定義好了,還記不記得上篇文章提到的類型定義完成後該怎麼辦?
對,建立查詢的 schema。
graphqlschema,
fields: {
}
const schema = new graphqlschema({
query: helloworldtype
schema 設定好了,是不是想查詢看看哪?
東風當然是伺服器啦。graphql 官方提供 express-graphql 這個中間件來支援基于 graphql 的查詢,是以,這裡選用 express 作為伺服器。
安裝就不再重複了,隻需将剛剛建立的 schema 添加到 express 的中間件中就可以了。
const app = express();
app
.use('/graphql', graphqlhttp({ schema, pretty: true }))
.listen(3000, () => {
console.log('graphql server running on http://localhost:3000/graphql');
});
當當當當~完成,去 postman 裡查詢 http://localhost:3000/graphql?query={hello} 看看吧。
blog system
在上一篇文章裡,我們設計了一個部落格的查詢 schema,這次我們就來動手實作它。(下面就開始講例子啦,不願聽我唠叨的可以直接看代碼)
前面 helloworld 的例子講的比較詳細,現在大家熟悉了文法,接下來的案例就會過得快一些。
首先是 posttype,這裡對 posttype 做了一點小修改,給幾個字段添加了不能為空的設計。
/**
* type post {
* id: id!,
* name: string!,
* createdate: string!,
* title: string!,
* subtitle: string,
* content: string,
* tags: [tag]
* }
*/
const post = new graphqlobjecttype({
name: 'posttype',
id: {
type: new graphqlnonnull(graphqlid)
},
name: {
type: new graphqlnonnull(graphqlstring)
createdate: {
title: {
subtitle: {
type: graphqlstring
content: {
tags: {
type: new graphqllist(tagtype),
resolve: post => post.tags.map(tagname => gettagbyname(tagname))
然後是另一個主要的 type: tag type。
* type tag {
* label: string!,
* posts: [post]
const tag = new graphqlobjecttype({
name: 'tagtype',
label: {
posts: {
type: new graphqllist(posttype),
resolve: tag => getpostslist().filter(post => ~post.tags.indexof(tag.name))
兩個主要的類型已經定義好了,把它們倆整合起來就是部落格類型了。
* type blog {
* post: post, // 查詢一篇文章
* posts: [post], // 查詢一組文章,用于部落格首頁
* tag: tag, // 查詢一個标簽
* tags: [tag], // 查詢所有标簽,用于部落格标簽頁
const blogtype = new graphqlobjecttype({
name: 'blogtype',
post: {
type: posttype,
args: {
name: {
type: graphqlstring
}
resolve: (blog, { name }) => getpostbyname(name),
resolve: () => getpostslist(),
tag: {
type: tagtype,
resolve: (blog, { name }) => gettagbyname(name),
resolve: () => gettagslist(),
這裡有一個新東西,就是 arg 字段,用來擷取查詢參數,如果在沒有設定過 arg 字段的屬性上添加變量進行查詢,graphql-js 的驗證系統會報錯。
最後,将之前的 helloworld 類型稍微修飾一下,獨立出來,然後和 blog type 整合到一起成為根查詢類。
const querytype = new graphqlobjecttype({
name: 'rootquerytype',
hello: worldtype,
blog: {
type: blogtype,
resolve: () => ({})
query: querytype
ok。這樣整個 demo 就完成了(檢視源碼戳這裡),快去 postman 試試各種查詢,體驗 graphql 的神奇吧。(不知道怎麼寫查詢語句的就看上一篇吧)
最後
如果,你不喜歡 get 方法或查詢字元串過長,express-graphql 也支援 post 方法,伺服器會先檢視請求的 url
中是否包含查詢字元串,如果不包含就會去 request body 中擷取,隻需在 request header 中将 content-type
設定為 application/graphql 就可以了。
全文一直在說查詢,或許你會疑惑,那我修改怎麼做哪?graphql 中的修改稱之為 mutation。mutation
可以定義自己的接口解析類,它在 graphql 的 schema 中是一個可選項,其他的和查詢并無兩樣,隻是最後在 resolve
方法中的處理方式不同而已。
query: querytype,
mutation: mutationtype
最後的最後提一句,nodemon 很好用,誰用誰知道。
作者:discipled
來源:51cto