Apollo-GraphQL
Apollo-GraphQL 是基于 GraphQL 封装的一种实现,它可以在服务上进行分层,包括 REST api 和 数据库,它包含客户端和服务端,还有 GUI 开发工具,让开发人员可以快速上手进行开发。
- 以搭建博客网站为例,有博客列表、分类、博客信息 (query)
- 点击某个博客,跳转到具体文章内容,返回时有已读标注 (mutation)
- 服务端使用 apollo-server-express
- 客户端使用 vue-apollo
- 数据为静态 json
搭建服务端:
- 创建一个文件夹,使用
npm init -y
初始化该文件夹 - 我们采取
apollo-server-express
来快速搭建服务端
安装需要的包:npm install apollo-server-express express graphql
- 创建入口文件app.js
const express = require("express");
const { ApolloServer } = require("apollo-server-express");
const typeDefs = require("./schema");
const resolvers = require("./resolvers");
const PORT = 4000;
const app = express();
const server = new ApolloServer({
typeDefs,
resolvers,
playground: {
endpoint: `/graphql`,
settings: {
"editor.theme": "light"
}
}
});
server.applyMiddleware({ app });
app.listen(PORT, () =>
console.log(
`http://localhost:${PORT}${server.graphqlPath}`
)
);
- 由于是博客的例子,因此这里先把 json格式的数据源造好。我们将数据放入data文件夹下。
[
{
"id": 1,
"title": "js基础部分知识总结",
"date": "2019-07-11",
"introduction": "学习来一段时间的js,这篇博客将对vue进行一个小小的总结。",
"category": "vue",
"isRead": false
}
]
[
{
"id": 1,
"html": "<h1>js基础部分知识总结</h1>"
}
]
- 对于apollo-server,最重要的也就是去定义 schema 和 resolvers ,我们要搞清楚如何去定义它们。
- 定义
schema.js
:
我们要把 schema文件里面的type 转换为 typeDefs要用到的形式, 就需要用到apollo-server-express
const { gql } = require("apollo-server-express");
module.exports = gql `
type Article {
id: Int!
title: String!
date: String!
introduction: String!
category: String
isRead: Boolean!
}
type ArticleContent {
id: Int!
html: String!
}
type Category {
num: Int!,
name: String!
}
type Query {
fetchArticles: [Article]
getAllCategories: [Category]
getArticleContent(id: Int!): ArticleContent
}
type Mutation {
articleIsRead(id: Int!): Article
}
`
- 定义
resolvers.js
resolvers 其实就是 query 和 mutation 的实现过程。也就是说这里会进行数据库的查询或者是 api 的调用等等,最终放回的结果在这里出来。
const articles = require("./data/articles.json");
const articleContent = require("./data/articleContent.json");
const resolvers = {
Query: {
fetchArticles() {
return articles;
},
getAllCategories() {
return articles.reduce((pre, cur) => {
const cate = pre.find(_ => _.name === cur.category);
if (cate) {
cate.num++;
} else {
const obj = {
name: cur.category,
num: 1
};
pre.push(obj);
}
return pre;
}, []);
},
getArticleContent(_, { id }) {
return articleContent.find(val => val.id === id);
}
},
Mutation: {
// 标记已读
articleIsRead(_, { id }) {
const article = articles.find(val => val.id === id);
if (!article) {
throw new Error(`找不到id为 ${id} 的文章`);
}
if (article.isRead) {
return article;
}
article.isRead = true;
return article;
}
}
};
module.exports = resolvers;
- 现在我们就可以使用
nodemon app.js
来启动服务器查看。
搭建客户端:
使用 vue 来搭建项目:
- 创建一个文件夹,使用
vue create blog
来创建一个vue的文件。 - 使用
npm add vue-apollo graphql apollo-boost
安装需要用到的包。 - 在
main.js
中配置文件
import Vue from "vue";
import App from './App.vue';
import ApolloClient from "apollo-boost";
import VueApollo from "vue-apollo";
Vue.use(VueApollo);
//创建ApolloClient实例
const apolloClient = new ApolloClient({
// 在这里需要使用绝对路径
uri: "http://localhost:4000/graphql"
});
//保存了可以在接下来被所有子组件使用的 Apollo 客户端实例。
const apolloProvider = new VueApollo({
defaultClient: apolloClient
});
//使用 apolloProvider 选项将它添加到应用程序
new Vue({
el: "#app",
apolloProvider,
render: h => h(App)
});
- 我们需要在vue文件的根目录下创建一个
vue.config.js
文件,用来配置支持 .gql || .graphql 文件后缀的 webpack。这样就可以导入xxx.gql的文件了,不一定非要在.vue文件或者.js文件里面写查询语句。
module.exports = {
// 支持 gql 文件
chainWebpack: config => {
config.module
.rule("graphql")
.test(/\.(graphql|gql)$/)
.use("graphql-tag/loader")
.loader("graphql-tag/loader")
.end();
}
};
- 接下来就试一下查询多个数据,比如说一起查询博客文章列表和分类信息。我这里是直接放到
app.vue
页面中使用。
import gql from "graphql-tag";
const fetchDataGql = gql`
{
fetchArticles {
id
title
date
introduction
category
isRead
}
getAllCategories {
num
name
}
}
`;
export default {
data() {
return {
articles: [],
categories: []
};
},
apollo: {
fetchData() {
const vm = this;
return {
query: fetchDataGql,
update(data) {
vm.articles = data.fetchArticles;
vm.categories = data.getAllCategories;
}
};
}
}
};
-
打开浏览器控制台查看。确实是只有一次请求就能获取到一个页面上所有的资源!在做项目的时候,遇到一个页面要请求多个REST接口,有些接口经常返回了很多页面上用不到的数据,也就是多余的数据。这样不仅浪费了服务器资源,前后端对接起来也不方便,所以 GraphQL 可以很好地解决这个点。
-
将获取到的数据渲染到页面中,这里使用的是vuetify,先使用
vue add vuetify
安装好vuetify的插件,然后就可以进行使用渲染页面了。
8. 查询搞定了,下面可以看看变更mutation,当我们点击某篇文章的小圆心的时候,让它改变颜色,并且弹出一个true。我们只需要继续在app.vue中进行定义。
const mArticleISRead = gql`
mutation articleIsRead($id: Int!) {
articleIsRead(id: $id) {
id
title
date
introduction
category
isRead
}
}
`
methods: {
mutationIsRead(id) {
this.$apollo.mutate({
mutation: mArticleISRead,
//传递参数
variables: {
id
},
update: (store, { data: { articleIsRead } }) => {
alert(articleIsRead);
}
});
}
}
当我们点击了小圆心的时候颜色会变成红色,并且会弹出true。