package.jsonvue
"dependencies": {
"apollo-server-koa": "^1.3.6",
"graphql": "^0.13.2",
"graphql-import": "^0.6.0",
"graphql-tools": "^3.0.2",
"koa": "^2.5.1",
"koa-bodyparser": "^4.2.1",
"koa-router": "^7.4.0",
"koa-websocket": "^5.0.1"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-env": "^1.7.0"
}
复制代码
server.jsjava
import koa from 'koa' import koaRouter from 'koa-router' import koaBody from 'koa-bodyparser' import websocketify from 'koa-websocket' import { graphqlKoa, graphiqlKoa } from 'apollo-server-koa' import { makeExecutableSchema } from 'graphql-tools' const app = websocketify(new koa()) const router = new koaRouter() const PORT = 3000 // fake data const moments = [ { user: { id: 1000, name: '锐雯', avatar: 'http://imgsrc.baidu.com/imgad/pic/item/42a98226cffc1e17d31927154090f603738de974.jpg' }, main: { content: '这是一条朋友圈', pics: [ 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1529219875063&di=bc0bcc78ae800c1c21c198f52697f515&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F4a36acaf2edda3ccd53548ea0be93901203f9223.jpg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1529219893624&di=8d9e418df27e1fdb6afb1d993801a980&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F3801213fb80e7beca9004ec5252eb9389b506b38.jpg' ] }, comments: [ { user: { id: 233122, name: '亚索' }, reply: '面对疾风吧' } ] } ] const typeDefs = ` type Query { moments: [Moment] } type Mutation { addComment( entity: Add_Comment ) : Comment } type Moment { user: User main: Main comments: [Comment] } type User { id: Int name: String avatar: String } type Comment { user: User reply: String } type Main { content: String pics: [String] } input Add_User { id: Int name: String } input Add_Comment { user: Add_User reply: String } # 定义graphqlf服务哪一个是RootQuery以及RootMutation schema { query: Query mutation: Mutation } ` const resolvers = { Query: { moments () { return moments } }, Mutation: { addComment (_, { entity }, unknown, context) { console.log(entity) moments[0].comments.push(entity) return entity } } } const schema = makeExecutableSchema({ typeDefs, resolvers }) // koaBody is needed just for POST. router.post('/graphql', koaBody(), graphqlKoa({ schema: schema })) // router.get('/graphql', graphqlKoa({ schema: schema })) router.get('/graphiql', graphiqlKoa({ endpointURL: '/graphql' })) async function responseMiddleware(ctx, next) { ctx.set('Access-Control-Allow-Origin', 'http://localhost:8080') ctx.set('Access-Control-Allow-Methods', 'POST,OPTIONS') ctx.set('Access-Control-Allow-Headers', 'authorization,content-type') // ctx.set('Access-Control-Allow-Credentials', 'true') await next() } app.use(responseMiddleware) app.use(router.routes()) app.use(router.allowedMethods()) app.ws.use(responseMiddleware) app.ws.use(router.routes()) app.ws.use(router.allowedMethods()) app.listen(PORT) 复制代码
包括有fields,alias,arguments,fragments,variables,directives,inline fragmentsweb
主要由RootQuery + RootMutation两种入口类型(操做)加上RootValue(resolvers)构成GraphQL Schema。(此处用graphql-tools是为了将全部的类型定义在一个字符串中,后续会移到一个.graphql文件中,而后用graphql-import导入)vue-cli
标量类型(Scalar Types)shell
Int
: 有符号的32位整数Float
: 有符号双精度浮点值String
: UTF-8字符序列Boolean
: true or falseID
:ID 标量类型表示一个惟一标识符(相似一种UUID),一般用以从新获取对象或者做为缓存中的键。ID 类型使用和 String 同样的方式序列化。枚举类型(Enumeration Types)npm
是一种特殊的标量类型json
enum Episode {
NEWHOPE
EMPIRE
JEDI
}
复制代码
用方括号[]
标记列表数组
是一种抽象类型,与java的interface机制相似。缓存
{
search(text: "an") {
... on Human {
name
height
}
... on Droid {
name
primaryFunction
}
... on Starship {
name
length
}
}
}
复制代码
与以前提到的全部Types对立,这是一种也是惟一一种输入类型,其主要用于mutations
时传递整个对象
的case,它没有参数。babel
!
: 表示非空。以下query DroidById($id: ID!) {
droid(id: $id) {
name
}
}
复制代码
GraphQL中每一个查询字段是返回子类型的父类型函数。每一个类型的字段对应由一个resolver
函数支持,当字段被执行时,响应的resolver
被调用并return结果。
若是字段产生结果为标量类型
值,好比字符串或数字,则执行完成。不然递归
执行对应解析器直至结果为标量类型
值。
每一个GraphQL服务端应用的顶层一定会有一个入口点
,一般为Root或者Query类型,接着执行该字段预设的解析器
(同步或异步),而每一个字段被解析的结果被放置在键值映射中,字段名(或别名)做为键,解析器的值做为值,这个过程从查询字段的底部叶子节点
开始返回,直到Query类型的起始节点
,最后生成镜像查询结果
返回给客户端
安装vue-cli3.x
npm i -g @vue/cli
复制代码
初始化工程
vue create [project-name]
复制代码
引入apollo插件
cd [project-name]
vue add apollo
复制代码
FriendCircle.vue
<template>
<div>
<div v-for="(item, index) in moments" :key="index">
{{item}}
</div>
<input type="text" v-model="comment.reply" placeholder="请输入要回复的内容">
<button @click="addComment">回复</button>
</div>
</template>
<script>
import gql from 'graphql-tag'
const QUERY_LIST = gql`
query {
moments {
user {
id
name
avatar
}
main {
content
pics
}
comments {
user {
id
name
}
reply
}
}
}
`
export default {
data () {
return {
moments: [],
comment: {
user: {
id: (Math.random() * 10000).toFixed(0),
name: '费德提克'
},
reply: ''
}
}
},
apollo: {
moments: {
query: QUERY_LIST
}
},
methods: {
addComment () {
this.$apollo.mutate({
mutation: gql`
mutation addComment($comment: Add_Comment) {
addComment(entity: $comment) {
user {
id
name
}
reply
}
}
`,
variables: {
comment: this.comment
},
update: (store, { data: { addComment } }) => {
// Read the data from our cache for this query.
const data = store.readQuery({ query: QUERY_LIST })
// set first moment's comment
data.moments[0].comments.push(addComment)
// Write our data back to the cache.
store.writeQuery({ query: QUERY_LIST, data })
}
})
}
}
}
</script>
复制代码
涉及的知识点有Root_Query,Root_Mutation,variables以及store cache
其核心机制包括如下两点
this.$apollo.mutate(options) options中有一个update回调,在成功响应数据后触发,而且能够直接读取并操做由apollo-cache-inmemory
生成的store。上述例子中使用此回调同步更新缓存以及UI
注:全部绑定的变量均不可直接修改,内部使用Object.freeze将对象冻结,没法直接增删。