你知道吗?FaceBook、GitHub,Pinterest,Twitter,Sky,纽约时报,Shopify,Yelp这些大公司已经在使用GraphQL规范的接口规范了。再不学习就落后了。javascript
在前端的开发中是否会遇到这样的困扰?php
若是须要实现支付状态、或者多人协做 、实时同步股票信息向客户端推送数据时,每每须要使用WebSocket通信或者其余通信方式。这时你会发现若是向服务器请求使用Restful风格没法保证接口风格统一。css
英文:graphql.org/html
中文: graphql.cn/前端
Github GraphQL Explorer developer.github.com/v4/explorer…java
GraphQL 是由 Facebook 创造的用于 API 的查询语言。react
先后端数据查询方式的规范。ios
GraphQL 既是一种用于 API 的查询语言也是一个知足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端可以准确地得到它须要的数据,并且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。git
# 查询
query {
book(id: "1") {
id,
author,
}
}
# 结果
{
"data": {
"book": {
"id": "1",
"author": "Author1"
}
}
}
复制代码
# 查询
query {
book(id: "1") {
id,
author,
},
book2 : book(id:"3"){
id
}
}
# 结果
{
"data": {
"book": {
"id": "1",
"author": "Author1"
},
"book2": {
"id": "3"
}
}
}
复制代码
给你的 GraphQL API 添加字段和类型而无需影响现有查询。老旧的字段能够废弃,从工具中隐藏。经过使用单一演进版本,GraphQL API 使得应用始终可以使用新的特性,并鼓励使用更加简洁、更好维护的服务端代码。github
GraphQL | Restful | |
---|---|---|
一次请求多资源 | ✔️ | ❌ |
API字段定制化 | ✔️ | ❌ |
精肯定义返回类型 | ✔️ | ❌ |
无需划分版本 | ✔️ | ❌ |
类型验证机制 | ✔️ | ❌ |
支持双向通信 | ✔️ | ❌ |
[进阶阅读复杂语法 Fragments Directives Function] juejin.cn/post/684490…
query {
books {
title,
author
}
}
### Result
{
"data": {
"books": [
{
"title": "abc",
"author": "xxxx"
}
]
}
}
复制代码
# 查询
query($id:String) {
book(id: $id) {
id,
author,
},
book2 : book(id:"3"){
id
}
}
# 变量
{
"id":"1"
}
# 结果
{
"data": {
"book": {
"id": "1",
"author": "Author1"
},
"book2": {
"id": "3"
}
}
}
复制代码
对于数据改变这种非幂等性操做使用Mutation来进项描述。
REST 中,任何请求均可能最后致使一些服务端反作用,可是约定上建议不要使用 GET 请求来修改数据。GraphQL 也是相似 —— 技术上而言,任何查询均可以被实现为致使数据写入。然而,建一个约定来规范任何致使写入的操做都应该显式经过变动(mutation)来发送。
# 查询
mutation {
createBook(title:"TTTT",author: "AAA") {
id
}
}
复制代码
若是数据发生变化但愿后台主动通知前端,你可使用Subscription后台消息订阅功能。
subscription {
subsBooks
}
复制代码
ApolloServer是一个开源的GraphQL框架。ApolloServer能够单独的做为服务器,同时ApolloServer也能够做为Express,Koa等Node框架的插件。
const { ApolloServer, gql } = require('apollo-server');
// Schema定义
const typeDefs = gql`
type Query {
hello: String,
}
`;
// 解释器实现
const resolvers = {
Query: {
hello: () => 'Hello world!',
}
};
// 建立服务器实例
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
复制代码
GraphQL也有几个基础类型,在GraphQL中他们统称叫标量类型(Scalar Type)
咱们能够根据须要将数据类型组合为对象这些统称为对象类型。
type Book {
id:String
title: String
author: String
}
复制代码
为了达到更好的代码复用GraphQl还提供更为复杂的接口类型这里面就不在一一赘述。
// index.js
// 添加Schema
const typeDefs = gql` type Query { books: [Book], book(id : String) : Book } type Book { id:String title: String author: String } `;
// 建立数据
const books = (
() => Array(5).fill().map((v, i) => ({
id: '' + i,
title: 'Title' + i,
author: 'Author' + i
}))
)()
// 添加resolve
const resolvers = {
Query: {
books: () => books,
book: (parent, { id }) => {
return books.find(v => v.id === id)
}
},
}
复制代码
const typeDefs = gql` type Mutation { createBook(title: String, author: String): Book!, clearBook : Boolean } `
resolvers.Mutation = {
createBook: (parent, args) => {
const book = { ...args, id: books.length + 1 + '' }
books.push(book)
return book
},
clearBook: () => {
books.length = 0
return true
}
}
复制代码
const { ApolloServer, gql, PubSub, withFilter } = require('apollo-server');
const typeDefs = gql` type Subscription { subsBooks : Boolean, } `;
const pubsub = new PubSub()
resolvers.Mutation = {
createBook: (parent, args) => {
const book = { ...args, id: books.length + 1 + '' }
books.push(book)
// 发布订阅消息
pubsub.publish('UPDATE_BOOK', {
subsBooks: true
})
return book
},
clearBook: () => {
books.length = 0
// 发布订阅消息
pubsub.publish('UPDATE_BOOK', {
subsBooks: true
})
return true
}
}
resolvers.Subscription = {
subsBooks: {
// 过滤不须要订阅的消息
subscribe: withFilter(
(parent, variables) => pubsub.asyncIterator('UPDATE_BOOK'),
(payload, variables) => true
)
},
}
复制代码
<script src="https://cdn.bootcss.com/axios/0.19.0/axios.min.js"></script>
<script> axios .post("http://localhost:4000/graphql", { query: `query { books { id title author } }` }) .then(res => { console.log("res: ", res); document.writeln(JSON.stringify(res.data)) }); </script>
复制代码
<script src="https://cdn.bootcss.com/axios/0.19.0/axios.min.js"></script>
<script> axios .post("http://localhost:4000/graphql", { query: `mutation($title:String,$author:String) { createBook(title:$title,author:$author){ id } }`, variables: { title: "TTTTT", author: "AAAAA" } }) .then(res => { console.log("res: ", res); document.writeln(JSON.stringify(res.data)) }); </script>
复制代码
[响应式 GraphQL 结构
在使用Apollo时咱们能够尝试一种彻底不一样的前端数据管理方式,即声明式数据管理。在传统的项目中咱们一般会将数据存放在Redux这样的统一状态管理模块中。利用ApolloClient经过GraphQL数据声明的方式管理数据。每一个模块均可以根据本身的需求定制好本身想要的数据。
const client = new ApolloClient({
uri: 'http://localhost:4000/graphql',
});
ReactDOM.render(
<React.StrictMode> <ApolloProvider client={client}> <App /> </ApolloProvider> </React.StrictMode >, document.getElementById('root') ); 复制代码
须要使用Subscription的时候须要符合链接
// Subscription
// Create an http link:
const httpLink = new HttpLink({
uri: 'http://localhost:4000/graphql'
});
// Create a WebSocket link:
const wsLink = new WebSocketLink({
uri: `ws://localhost:4000/graphql`,
options: {
reconnect: true
}
});
// using the ability to split links, you can send data to each link
// depending on what kind of operation is being sent
const link = split(
// split based on operation type
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink,
httpLink,
);
// Subscription
const cache = new InMemoryCache();
const client = new ApolloClient({
link,
cache
});
复制代码
import React, { useEffect } from 'react';
import { useQuery } from '@apollo/react-hooks';
import { gql } from 'apollo-boost';
const QUERY = gql` query { books { id, author, title } } `;
function Query() {
const { loading, error, data, refetch } = useQuery(QUERY)
useEffect(() => {
refetch()
})
if (loading) return <p>Loading...</p>
if (error) return <p>Error :(</p>
console.log('book', data)
const list = data.books.map(v => (
<div>{v.author}: {v.title}</div>
))
return list
}
export default Query;
复制代码
import React from 'react';
import { useMutation } from '@apollo/react-hooks';
import { gql } from 'apollo-boost';
const CREATE_BOOK = gql`
mutation CreateBook($title:String!,$author:String!){
createBook(title:$title,author:$author){
id,
title,
author
}
}
`;
const CLEAR_BOOK = gql`
mutation {
clearBook
}
`;
function Mutation() {
const [create, { data }] = useMutation(CREATE_BOOK);
const [clear] = useMutation(CLEAR_BOOK)
return (
<div>
<form
onSubmit={e => {
e.preventDefault();
create({
variables: {
"title": 'Title' + (Math.random() * 100).toFixed(),
"author": 'Author'+ (Math.random() * 100).toFixed()
}
});
console.log('mutation:',data)
}}
>
<button type="submit">Create</button>
</form>
<button onClick={ clear }>Clear</button>
</div>
);
}
export default Mutation;
复制代码
import React from 'react';
import { useSubscription } from '@apollo/react-hooks';
import { gql } from 'apollo-boost';
import Query from './Query'
const subs = gql` subscription { subsBooks } `;
function Subscription() {
useSubscription(subs)
return <Query/>
}
export default Subscription;
复制代码
Apollo资源参考这篇文章 juejin.cn/post/684490…
服务端
客户端
Prisma 弥合了数据库和GraphQL resolvers之间的鸿沟,让实现生产级别的GraphQL服务器变得更加容易。 除了强大的查询引擎和API,Prisma在开发体验方面尤其突出。www.prisma.io/
typeorm 直接复用typegraphql中建立的model