最近剛完成一個新項目,閒着沒事,想着學點新東西(作前端的人都懂,技術更新實在太快了,不學容易out),據說GraphQL
如今開始火起來,大有取代傳統Restful API
的方式的趨勢,因此我決定學學。css
GraphQL 是由 Facebook 創造的用於 API 的查詢語言(這裏查詢語言所指的並非常規意義上的相似 sql 語句的查詢語言,而是一種用於先後端數據查詢方式的規範)。
GraphQL 既是一種用於 API 的查詢語言也是一個知足你數據查詢的運行時。 GraphQL 對你的 API 中的數據提供了一套易於理解的完整描述,使得客戶端可以準確地得到它須要的數據,並且沒有任何冗餘,也讓 API 更容易地隨着時間推移而演進,還能用於構建強大的開發者工具。
複製代碼
更多關於GraphQL
的介紹你們能夠看這裏前端
因爲GraphQL
只是一套規範,不能直接使用,但社區有了不少編程語言的實現,能夠直接拿過來用。這裏我選用了Apollo
。node
Apollo 是基於 GraphQL 的全棧解決方案集合。包括了 apollo-client 和 apollo-server ;從後端到前端提供了對應的 lib 使得開發使用 GraphQL 更加的方便。
複製代碼
GraphQL
須要先後端一塊兒才能真正發揮它的的做用,咱們先在服務端實現它,這裏就要用到apollo-server
。react
apollo-server是一個在Node.js
上構建GraphQL
服務端的web中間件。支持express
,koa
,hapi
等框架。這裏我用的是koa
。web
首先,咱們要安裝依賴包sql
yarn add koa koa-bodyparser koa-router apollo-server-koa graphql graphql-tools
//or
npm install koa koa-bodyparser koa-router apollo-server-koa graphql graphql-tools
複製代碼
而後,編寫代碼express
// server.js
const Koa = require('koa');
const Body = require('koa-bodyparser');
const router = require('koa-router')();
const {graphqlKoa, graphiqlKoa} = require('apollo-server-koa');
const {makeExecutableSchema} = require('graphql-tools');
const { GraphQLScalarType } = require('graphql');
const { Kind } = require('graphql/language');
const app = new Koa();
const PORT = 8090;
// 模擬數據
const users = [
{
id: 1,
name: 'J.K. Rowling',
date: new Date(2018, 5, 20)
},
{
id: 2,
name: 'Michael Crichton',
date: new Date(2018, 5, 21)
},
];
const typeDefs = `
scalar Date
type User{
id:Int!
name:String!
date: Date!
}
type Query {
users(id:Int!): [User]
user(id:Int!, name: String!):User
}
type Mutation {
addUser(name:String!):User
}
schema {
query: Query
mutation: Mutation
}
`;
const resolvers = {
Query: { // 對應到typeDefs中的 type Query
users(root, args, context) {
return users;
},
user(root, args, context, info) {
return {id: args.id, name: args.name};
}
},
Mutation: { // 對應到typeDefs中的 Mutation
addUser(root, args, context) {
return {id: 2, name: args.name};
}
},
Date: new GraphQLScalarType({ // 自定義標量類型
name: 'Date',
description: 'Date custom scalar type',
parseValue(value) {
return new Date(value); // 從客戶端來的數據
},
serialize(value) {
return value.getTime(); // 發送給客戶端的數據
},
parseLiteral(ast) {
if (ast.kind === Kind.INT) {
return parseInt(ast.value, 10);
}
return null;
},
}),
};
const myGraphQLSchema = makeExecutableSchema({
typeDefs,
resolvers
});
app.use(Body());
router.post('/graphql', graphqlKoa({
schema: myGraphQLSchema,
}));
router.get('/graphql', graphqlKoa({
schema: myGraphQLSchema,
}));
router.get( // 在瀏覽器裏使用GraphiQL(能夠理解成GraphQL領域的postman)
'/graphiql',
graphiqlKoa({
endpointURL: '/graphql',
}),
);
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(PORT, ()=>console.log('app run in localhost:' + PORT));
複製代碼
接下來,執行下面命令來讓咱們的服務端跑起來:npm
node server.js
app run in localhost:8090
複製代碼
而後在瀏覽器裏輸入http://localhost:8090/graphiql
,你會看到以下界面: 編程
GraphQL
服務已成功啓動。你能夠在界面上進行相應的數據查詢。
服務端已經成功啓動,接下來就是咱們的客戶端了,前端本人使用的是React
框架,爲了方便因此項目直接使用create-react-app
建立。後端
建立完成後咱們進入項目目錄,接着安裝客戶端GraphQL
查詢所須要的依賴包:
yarn add react-apollo graphql-tag graphql apollo-client apollo-cache-inmemory apollo-link-http
// or
npm install react-apollo graphql-tag graphql apollo-client apollo-cache-inmemory apollo-link-http
複製代碼
接下來咱們修改src/index.js
裏的代碼:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';
const httpLink = new HttpLink({ uri: 'http://localhost:8090/graphql' })
const client = new ApolloClient({
link: httpLink,
cache: new InMemoryCache()
})
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>
, document.getElementById('root'));
registerServiceWorker();
複製代碼
而後修改src/App.js
裏的代碼:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import gql from 'graphql-tag';
import { graphql } from 'react-apollo';
class App extends Component {
render() {
console.log(this.props);
const { loading } = this.props.data;
if (loading) {
return <div>Loading...</div>
}
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<p>{this.props.data.user.name}</p>
</div>
);
}
}
export default graphql(gql`
query User{
user(id: 100, name: "zhangsfs") {
id
name
}
users(id: 100) {
id
name
date
}
}
`)(App);
複製代碼
常常包裝後的App組件會被注入一個名爲data
的props
,它包含下面這些字段:
loading
字段爲
true
是表示在正在查詢,爲
false
表示查詢完成。
而後運行前端代碼:
yarn start
// Compiled successfully!
// You can now view client in the browser.
// Local: http://localhost:8081/
// On Your Network: http://172.22.228.1:8081/
複製代碼
在瀏覽器輸入http://localhost:8081/
結果發現頁面報錯,沒能正常運行,咱們打開開發者工具發現了其中一項報錯:
那麼如何才能實現跨域訪問呢?咱們須要在修改服務端代碼讓他支持跨域訪問。
首先在服務端增長一個依賴包:
yarn add @koa/cors@2
複製代碼
而後修改server.js代碼:
// server.js
const Koa = require('koa');
const Body = require('koa-bodyparser');
const router = require('koa-router')();
const cors = require('@koa/cors');
...
app.use(Body());
app.use(cors());
...
app.listen(PORT, ()=>console.log('app run in localhost:' + PORT));
複製代碼
而後從新啓動服務端代碼,刷新http://localhost:8081/
,發現項目能正常運行啦。至此一個簡單的GraphQL
查詢就算完成了。
上面只是一個很是簡單的GraphQL
查詢demo,由於本人也是初學,不少東西也還在學習階段。若是你們有什麼好的開發心得,歡迎交流。