apollo graphql mysql_GraphQL实战(后端篇:apollo-server-koa + koa)

本文介绍了如何使用GraphQL来弥补RESTFul接口的不足,特别是通过apollo-server-koa集成到koa 2.5.1项目中。详细讲解了GraphQL的优缺点,并展示了如何创建GraphQL查询和变更对象,以及如何与MySQL数据库配合。通过实例演示了如何在后端实现GraphQL服务器,包括引入插件、创建Apollo Server、定义GraphQL表、监听端口等步骤,最终实现自动生成API文档的功能。
摘要由CSDN通过智能技术生成

8d6f51fb0055

image

前言

什么是GraphQL?

简而言之就是用于API的查询语言。你可以理解为只需要一次请求加上点查询参数,就可以定制任何后端有的信息。

在继续讲GraphQL之前我们先来看看我们常用的RESTFul接口(REST和RESTFul的关系就像Beatuy和Beautiful的关系)的优缺点(没缺点我们换它干啥)

RESTFUL接口的优缺点

RESTFul接口在历史上最大的贡献在于实现了前后端分离以及后端的无状态设计(后端无状态设计就是后端的资源不需要建立session,完全依赖客户端的请求)。

优点:

不仅有http状态码可供错误机制处理还可以方便的自定义错误码

缺点 :

接口冗长。(随着业务的不断丰富,单个RESTFul接口可能变得越来越冗长)

文档难于维护。(RESTFul文档的维护缺失是个很耗人力的事)

无法自定义相应结果。(有时候我只需要一个用户名,接口RESTFul给我返回了一大堆不需要的字段)

效率低下。(如果用RESTFul接口的话,经常会遇到需要几个RESTFul接口才能完成的展示页面的情况)

针对RESTFul的缺点,GraphQL就应运而生了。来看下它的优缺点:

优点

自定义查询API,体验好。(后端性能是否提高暂且不论,但是前后端代码减少了不少,一个接口搞定所有需要的信息)

文档自动生成。(再也不需要人工维护文档了,可以往下看,有例子)

可以自定义查询结果。(接口调用者决定需要哪些字段,后端会根据前端的查询参数返回定制的字段)

缺点

无http状态码。(无论查询条件是否正确,http状态码返回的都是200,而且自定义的状态码不好处理)

无缓存(据说Apollo GraphQL这个项目已经集成了,具体插件是apollo-cache-inmemory);

以上大致讲了下GraphQL的一个优缺点,自然也能大致了解其应用场景,在GraphQL还没有完全解决它的缺点之前,我们可以将其和RESTFul接口搭配使用。接下来我们基于koa 2.5.1 和 apollo-server-koa 2.4.8 进行实战演练

由于我这个项目是之前基于RESTFul接口的,这里我将GraphQL集成到上面(也就是在后端返回和前端之间加入GraphQL这层拦截层)。

先看下项目结构

8d6f51fb0055

image

总共基于 koa 和 apollo-server-koa 操作有一下6个步骤

引入插件 apollo-sever-koa

创建apollo server并传入GraphQL表

创建koa对象

将koa对象作为中间件传入apollo server

监听端口

定义GraphQL表并传入query对象和Mutation对象

【细节】

安装插件 apollo-sever-koa 和 koa

cnpm install apollo-server-koa koa

创建app.js

const Koa = require('koa');

const {ApolloServer, gql} = require('apollo-server-koa'); // graphql-koa插件

const schema = require('./server/graphql/index.js'); //自定义的GraphQL的表

const server = new ApolloServer({ //创建Graphql server

schema,

context: ({ ctx }) => {

// let token = ctx.

}

});

server.applyMiddleware({app}); //apollo server使用koa中间件

app.listen(9527, ()=> { //监听端口

console.log(`server running success at ${server.graphqlPath}`)

})

创建GraphQL表

//index.js

const { articleList } = require('./schemas/articles');

const { postLogin } = require('./schemas/user');

const {

GraphQLSchema,

GraphQLObjectType

} = require('graphql');

//总查询对象

let queryObj = new GraphQLObjectType({

name: 'query',

fields: () => ({

articleList: articleList

})

})

//总体变更对象

let mutationObj = new GraphQLObjectType({

name: 'Mutation',

fields: () => ({

postLogin: postLogin

})

})

//GraphQL总表

let schema = new GraphQLSchema({

query: queryObj,

mutation: mutationObj

})

module.exports = schema

创建文章表

const {

GraphQLObjectType, //对象类型

GraphQLString, //字符串类型

GraphQLList, //数组类型

GraphQLInt //int类型

} = require('graphql');

//文章业务逻辑控制

const ArticleController = require('../../controller/article.js');

//定义评论对象

let commentType = new GraphQLObjectType({

name: 'commentType',

description:'评论对象',

fields() {

return {

name: { type: GraphQLString },

email: { type: GraphQLString },

comment_content: { type: GraphQLString }

}

}

})

//定义单个文章对象

let ArticlesType = new GraphQLObjectType({

name: 'single_article_type',

description: '单个文章对象', // 这里写详细点有助于自动生成文档,减少前后端沟通成本

fields() {

return {

_id: { type:GraphQLString },

page_view_time: { type: new GraphQLList(GraphQLString) },

user_view: { type: new GraphQLList(GraphQLString)},

comment: { type: new GraphQLList(commentType) },

page_view_count: { type: GraphQLInt },

md_content: { type: GraphQLString },

html_content: { type: GraphQLString },

update_time: { type: GraphQLString },

create_time: { type: GraphQLString },

title: { type: GraphQLString },

user_view_count: { type: GraphQLInt },

comment_count: { type: GraphQLInt }

}

}

})

//定义文章列表对象

let articleList = {

name: 'query articles list',

type: new GraphQLList(ArticlesType),

args: { //定义参数

id: {

name: 'id',

type: GraphQLString

},

limit: {

name: 'limit',

type: GraphQLInt,

},

skip: {

name: "skip",

type: GraphQLInt

}

},

async resolve(root, params, options) {

let result = await ArticleController.queryArticle({

id: params.id,

limit: params.limit,

skip: params.skip

});

return result;

}

}

module.exports = {

articleList

}

创建用户表

const {

GraphQLSchema,

GraphQLObjectType,

GraphQLString,

GraphQLInt

} = require('graphql');

//用户逻辑控制

const UserController = require('../../controller/user.js');

const UserOutputType = new GraphQLObjectType({

name: 'user_operage_type',

fields() {

return {

name: { type: GraphQLString },

token: { type: GraphQLString }

}

}

})

const postLogin = {

description: 'postlogin',

type: UserOutputType,

args: {

username: {

name: 'username',

type: GraphQLString

},

password: {

name: 'password',

type: GraphQLString

}

},

async resolve(root, params, options) {

let user = await UserController.postLogin({

username: params.username,

password: params.password

});

return user;

}

}

module.exports = {

postLogin

}

看效果

8d6f51fb0055

test.gif

8d6f51fb0055

test2.gif

点击schema就可以查看所有字段,自动生成API文档!

8d6f51fb0055

test3.gif

网上很多express + graphql的例子但是基于koa 2.x和 apollo-server-koa 2.x的版本的例子比较少,这里我也是查阅了很多资料和官网实践整理出来的,若有意见或疑问欢迎留言。

参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值