你知道嗎?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