项目地址:https://github.com/kongpingfan/frontend/tree/master/GraphQL
运行:
npm install npm run dev
什么是GraphQL
GraphQL
可以更高效的设计和使用API,它是REST
的替代品,它具有以下优点:
- 只获取到想获取的内容。使用
REST
,通常获取的信息会过载,需要提取出有用的字段。 - 强类型(strongly-typed),在执行前可以做检查。
graphql的官网:https://graphql.org/
Getting started
学习GraphQL,需要有GraphQL的服务端。
可以使用Graphpack,它不需要进行配置:
https://github.com/glennreyes/graphpack
创建一个文件夹,名叫 graphql-server
。进行文件夹,进行npm初始化:
npm init -y
安装graphpack:
npm install --save-dev graphpack
安装完后,在package.json
中添加:
"scripts": {
"dev": "graphpack",
"build": "graphpack build"
}
创建一个src
文件夹,里面新建三个文件:
src
|--db.js
|--resolvers.js
|--schema.graphql
schema.graphql
:
type Query {
hello: String
}
resolvers.js
:
import { users } from "./db";
const resolvers = {
Query: {
hello: () => "Hello World!"
}
};
export default resolvers;
db.js
:
export let users = [
{ id: 1, name: "John Doe", email: "john@gmail.com", age: 22 },
{ id: 2, name: "Jane Doe", email: "jane@gmail.com", age: 23 }
];
db.js
只是为了模拟真实数据库的数据。
运行npm run dev
:
GraphQL
有自己的语法格式叫做Schema Definition Language (SDL)
类型
类型(types)是GraphQL最重要的特性之一。例如,创建一个User
类型,它可能有name,email,age
等字段。
现在将schema.graphql
改成这样:
type User {
id: ID!
name: String!
email: String!
age: Int
}
- 每行最后的
!
表示非空(non-nullable
)。 只有age字段允许为空
在GraphQL
中,主要有三个概念:
- queries — 从服务端获取数据(查询).
- mutations — 更新数据到服务器并获取最新数据(创建、更新、删除)
- subscriptions — 维护与服务器的实时连接.
Queries
在schema.graphql
中添加:
type Query {
users: [User!]!
}
users
查询会返回Users
数组,并不允许为空
也可以查询指定的user:
type Query {
users: [User!]!
user(id: ID!): User!
}
- 需要传入
ID
来查询特定user
那从哪里获取数据呢?这就是resolvers.js
做的事情,它告诉GraphQL
数据源在哪。
resolvers.js
更新为:
import { users } from "./db";
const resolvers = {
Query: {
user: (parent, { id }, context, info) => {
return users.find(user => user.id === id);
},
users: (parent, args, context, info) => {
return users;
}
}
};
export default resolvers;
-
在
user
函数里,传入id
参数,返回该用户。 -
users
函数,返回所有的user。
访问localhost:4000
,并输入下面查询语句:
query {
users {
id
name
email
age
}
}
返回结果如下:
{
"data": {
"users": [
{
"id": "1",
"name": "John Doe",
"email": "john@gmail.com",
"age": 22
},
{
"id": "2",
"name": "Jane Doe",
"email": "jane@gmail.com",
"age": 23
}
]
}
}
如果想查询特定用户:
query {
user(id: 1) {
id
name
email
age
}
}
但是查询出错。
Mutations
更新schema.graphql
:
type Mutation {
createUser(id: ID!, name: String!, email: String!, age: Int): User!
updateUser(id: ID!, name: String, email: String, age: Int): User!
deleteUser(id: ID!): User!
}
更新resolver.js
:
Mutation: {
createUser: (parent, { id, name, email, age }, context, info) => {
const newUser = { id, name, email, age };
users.push(newUser);
return newUser;
},
updateUser: (parent, { id, name, email, age }, context, info) => {
let newUser = users.find(user => user.id === id);
newUser.name = name;
newUser.email = email;
newUser.age = age;
return newUser;
},
deleteUser: (parent, { id }, context, info) => {
const userIndex = users.findIndex(user => user.id === id);
if (userIndex === -1) throw new Error("User not found.");
const deletedUsers = users.splice(userIndex, 1);
return deletedUsers[0];
}
}
到localhost:4000
测试:
mutation {
createUser(id: 3, name: "Robert", email: "robert@gmail.com", age: 21) {
id
name
email
age
}
}
返回:
{
"data": {
"createUser": {
"id": "3",
"name": "Robert",
"email": "robert@gmail.com",
"age": 21
}
}
}
删除操作:
mutation{
deleteUser(id: 3){
id
name
email
age
}
}
Subscriptions
当服务端产生一个事件时,服务端会将对应数据发送给客户端。通过这种订阅机制,应用可以确保是实时更新的。
例如:
subscription {
users {
id
name
email
age
}
}
它和query长的有点像,但是工作机制完全不同。
关于subscription更多的内容:https://hackernoon.com/from-zero-to-graphql-subscriptions-416b9e0284f3
Conclusion
它最终会替代`REST