GraphQL的JavaScript实现graphql-js应用举例


系列文章:

  1. GraphQL 核心概念
  2. graphql-js 浅尝(本文)

常言道,实践是检验真理的唯一标准。

上一篇文章讲了 GraphQL 的核心概念,所提到的一些例子都是理论化的,并没有实际代码做支撑,就好像在画一个大饼,总是让人不那么信服。

它真的有那么神奇吗?那就同我一起看下去,用事实说话。

之前那篇文章一直有提到 GraphQL 是一个概念,每个语言可以有自己实现它的方式。因为,我是搞前端的,对 JavaScript 比较熟悉,所以,这里就用 graphql-js(GraphQL 的 JavaScript 实现)来举例。

Hello World

遵循传统,第一个例子必须是 Hello World。

首先,安装就不用多说了。

 
 
  1. npm install graphql-js --save 

那这个例子该怎么设计哪?假设,查询一个 hello 字符串,就返回一个 world 字符串,很明显 type 的结构就该是这样

 
 
  1. type HelloWorld { 
  2.  
  3. hello: String 
  4.  

如何实现这个 HelloWorld 类型哪?graphql-js 已经定义好了基础类,我们直接调用就行。那么,这个 type 实现起来也就非常简单了

 
 
  1. import { 
  2.     GraphQLString, 
  3.     GraphQLObjectType, 
  4. from 'graphql'
  5.  
  6. const HelloWorldType = new GraphQLObjectType({ 
  7.     name'HelloWorldType'
  8.     fields: () => ({ 
  9.         hello: { 
  10.             type: GraphQLString, 
  11.         } 
  12.     }) 
  13. }); 

简单分析一下上面的代码,可以看到 HelloWorldType 是一个 GraphQLObjectType 的实例,它包含一个 fields 是 hello,这个 hello 所对应的返回类型是字符串。

那如何返回 world 字符串?那就给它个 resolve 方法

 
 
  1. const HelloWorldType = new GraphQLObjectType({ 
  2.     name'HelloWorldType'
  3.     fields: () => ({ 
  4.         hello: { 
  5.             type: GraphQLString, 
  6.             resolve() { 
  7.                 return 'world'
  8.             }, 
  9.         } 
  10.     }) 
  11. }); 

这样类型就定义好了,还记不记得上篇文章提到的类型定义完成后该怎么办?

对,创建查询的 schema。

 
 
  1. import { 
  2.     GraphQLString, 
  3.     GraphQLObjectType, 
  4.     GraphQLSchema, 
  5. } from 'graphql'; 
  6.  
  7. const HelloWorldType = new GraphQLObjectType({ 
  8.     name: 'HelloWorldType', 
  9.     fields: { 
  10.         hello: { 
  11.             type: GraphQLString, 
  12.             resolve() { 
  13.                 return 'world'; 
  14.             }, 
  15.         } 
  16.     } 
  17. }); 
  18. const schema = new GraphQLSchema({ 
  19.     query: HelloWorldType 
  20. }); 

schema 设置好了,是不是想查询看看哪?

东风当然是服务器啦。GraphQL 官方提供 express-graphql 这个中间件来支持基于 GraphQL 的查询,所以,这里选用 Express 作为服务器。

安装就不再重复了,只需将刚刚建立的 schema 添加到 express 的中间件中就可以了。

 
 
  1. const app = express(); 
  2.  
  3. app 
  4.     .use('/graphql', graphqlHTTP({ schema, pretty: true })) 
  5.     .listen(3000, () => { 
  6.         console.log('GraphQL server running on http://localhost:3000/graphql'); 
  7.     }); 

当当当当~完成,去 Postman 里查询 http://localhost:3000/graphql?query={hello} 看看吧。

Blog System

在上一篇文章里,我们设计了一个博客的查询 schema,这次我们就来动手实现它。(下面就开始讲例子啦,不愿听我唠叨的可以直接看代码)

前面 HelloWorld 的例子讲的比较详细,现在大家熟悉了语法,接下来的案例就会过得快一些。

首先是 PostType,这里对 Posttype 做了一点小修改,给几个字段添加了不能为空的设计。

 
 
  1. /** 
  2.  * type Post { 
  3.  *   id: ID!, 
  4.  *   name: String!, 
  5.  *   createDate: String!, 
  6.  *   title: String!, 
  7.  *   subtitle: String, 
  8.  *   content: String, 
  9.  *   tags: [Tag] 
  10.  * } 
  11.  */ 
  12. const Post = new GraphQLObjectType({ 
  13.     name'PostType'
  14.     fields: () => ({ 
  15.         id: { 
  16.             type: new GraphQLNonNull(GraphQLID) 
  17.         }, 
  18.         name: { 
  19.             type: new GraphQLNonNull(GraphQLString) 
  20.         }, 
  21.         createDate: { 
  22.             type: new GraphQLNonNull(GraphQLString) 
  23.         }, 
  24.         title: { 
  25.             type: new GraphQLNonNull(GraphQLString) 
  26.         }, 
  27.         subtitle: { 
  28.             type: GraphQLString 
  29.         }, 
  30.         content: { 
  31.             type: GraphQLString 
  32.         }, 
  33.         tags: { 
  34.             type: new GraphQLList(TagType), 
  35.             resolve: post => post.tags.map(tagName => getTagByName(tagName)) 
  36.         } 
  37.     }) 
  38. }); 

然后是另一个主要的 type: Tag type。

 
 
  1. /** 
  2.  * type Tag { 
  3.  *   id: ID!, 
  4.  *   name: String!, 
  5.  *   label: String!, 
  6.  *   createDate: String!, 
  7.  *   posts: [Post] 
  8.  * } 
  9.  */ 
  10. const Tag = new GraphQLObjectType({ 
  11.     name'TagType'
  12.     fields: () => ({ 
  13.         id: { 
  14.             type: new GraphQLNonNull(GraphQLID) 
  15.         }, 
  16.         name: { 
  17.             type: new GraphQLNonNull(GraphQLString) 
  18.         }, 
  19.         label: { 
  20.             type: new GraphQLNonNull(GraphQLString) 
  21.         }, 
  22.         createDate: { 
  23.             type: new GraphQLNonNull(GraphQLString) 
  24.         }, 
  25.         posts: { 
  26.             type: new GraphQLList(PostType), 
  27.             resolve: tag => getPostsList().filter(post => ~post.tags.indexOf(tag.name)) 
  28.         } 
  29.     }) 
  30. }); 

两个主要的类型已经定义好了,把它们俩整合起来就是博客类型了。

 
 
  1. /** 
  2.  * type Blog { 
  3.  *   post: Post,    // 查询一篇文章 
  4.  *   posts: [Post],    // 查询一组文章,用于博客首页 
  5.  *   tag: Tag,        // 查询一个标签 
  6.  *   tags: [Tag],    // 查询所有标签,用于博客标签页 
  7.  * } 
  8.  */ 
  9. const BlogType = new GraphQLObjectType({ 
  10.     name'BlogType'
  11.     fields: () => ({ 
  12.         post: { 
  13.             type: PostType, 
  14.             args: { 
  15.                 name: { 
  16.                     type: GraphQLString 
  17.                 } 
  18.             }, 
  19.             resolve: (blog, { name }) => getPostByName(name), 
  20.         }, 
  21.         posts: { 
  22.             type: new GraphQLList(PostType), 
  23.             resolve: () => getPostsList(), 
  24.         }, 
  25.         tag: { 
  26.             type: TagType, 
  27.             args: { 
  28.                 name: { 
  29.                     type: GraphQLString 
  30.                 } 
  31.             }, 
  32.             resolve: (blog, { name }) => getTagByName(name), 
  33.         }, 
  34.         tags: { 
  35.             type: new GraphQLList(TagType), 
  36.             resolve: () => getTagsList(), 
  37.         } 
  38.     }) 
  39. }); 

这里有一个新东西,就是 arg 字段,用来获取查询参数,如果在没有设置过 arg 字段的属性上添加变量进行查询,graphql-js 的验证系统会报错。

最后,将之前的 helloworld 类型稍微修饰一下,独立出来,然后和 blog type 整合到一起成为根查询类。

 
 
  1. const queryType = new GraphQLObjectType({ 
  2.     name'RootQueryType'
  3.     fields: () => ({ 
  4.         hello: WorldType, 
  5.         blog: { 
  6.             type: BlogType, 
  7.             resolve: () => ({}) 
  8.         }, 
  9.     }) 
  10. }); 
  11.  
  12. const schema = new GraphQLSchema({ 
  13.     query: queryType 
  14. }); 

OK。这样整个 Demo 就完成了(查看源码戳这里),快去 Postman 试试各种查询,体验 GraphQL 的神奇吧。(不知道怎么写查询语句的就看上一篇吧)

最后

如果,你不喜欢 GET 方法或查询字符串过长,express-graphql 也支持 POST 方法,服务器会先查看请求的 URL 中是否包含查询字符串,如果不包含就会去 request body 中获取,只需在 request header 中将 Content-Type 设置为 application/graphql 就可以了。

全文一直在说查询,或许你会疑惑,那我修改怎么做哪?graphql 中的修改称之为 mutation。mutation 可以定义自己的接口解析类,它在 graphql 的 schema 中是一个可选项,其他的和查询并无两样,只是最后在 resolve 方法中的处理方式不同而已。

 
 
  1. const schema = new GraphQLSchema({ 
  2.     query: queryType, 
  3.     mutation: mutationType 
  4. }); 

最后的最后提一句,nodemon 很好用,谁用谁知道。


作者:DiscipleD

来源:51CTO

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值