一種用於API調用的數據查詢語言css
傳統的api調用通常獲取到的是後端組裝好的一個完整對象,而前端可能只須要用其中的某些字段,大部分數據的查詢和傳輸工做都浪費了。graphQL提供一種全新數據查詢方式,能夠只獲取須要的數據,使api調用更靈活、高效和低成本。html
下面咱們經過搭建一個SpaceX的新聞網站來直觀學習graphQL的基本使用方法,全部數據由 官方API 得到。前端
服務端採用node + express。新建一個node項目,安裝以下依賴:node
$ npm i graphql express-graphql express axios
建立入口文件 server.js
,裏面建立express服務。使用graphQL咱們只須要設置一個路由,全部的請求都由這個graphQL的request handler處理:react
const express = require('express'); const graphqlHTTP = require('express-graphql'); const schema = require('./schema'); const app = express(); app.use('/graphql', graphqlHTTP({ schema, graphiql: true })); const PORT = process.env.PORT || 5000; app.listen(PORT,()=>console.log(`Server started on port ${PORT}`));
graphqlHTTP是grapql的http服務,用於處理graphql的查詢請求,它接收一個options參數,其中schema是一個 GraphQLSchema
實例,咱們接下來定義,graphiql設置爲true能夠在瀏覽器中直接對graphQL進行調試。更多express-graphql的用法請參考 Github express-graphql。ios
接下來咱們定義schema,schema意爲‘模式’,其中定義了數據模型的結構、字段的類型、模型間的關係,是graphQL的核心。git
新建schema.js
文件,首先定義兩個數據模型:LaunchType(發射)和 RocketType(火箭)。注意字段的數據類型須要使用GraphQL定義的,不能使用js中的基本數據類型。github
const { GraphQLObjectType, GraphQLInt, GraphQLString, GraphQLBoolean, GraphQLList, GraphQLSchema } = require('graphql'); const LaunchType = new GraphQLObjectType({ name: 'Launch', fields: () => ({ flight_number: { type: GraphQLInt }, mission_name: { type: GraphQLString }, launch_date_local: { type: GraphQLString }, launch_success: { type: GraphQLBoolean }, rocket: { type: RocketType }, }) }); const RocketType = new GraphQLObjectType({ name: 'Rocket', fields: () => ({ rocket_id: { type: GraphQLString }, rocket_name: { type: GraphQLString }, rocket_type: { type: GraphQLString } }) });
有了數據模型以後,咱們須要從數據庫或者第三方API獲取數據,在此咱們從spacex的官方API獲取。咱們須要定義一個root query,root query作爲全部查詢的入口,處理並返回數據,更多請參考 GraphQL Root fields & resolvers。數據庫
在 schema.js
中增長代碼:express
const axios = require('axios'); ... const RootQuery = new GraphQLObjectType({ name: 'RootQueryType', fields: { launches: { type: new GraphQLList(LaunchType), resolve(parent, args) { return axios.get('https://api.spacexdata.com/v3/launches').then(res => res.data); } } } }); module.exports = new GraphQLSchema({ query: RootQuery });
完成這一步,服務端api基本搭建完成!咱們看一下效果,在瀏覽器中輸入 http://localhost:5000/graphql 將打開 Graphiql(生產環境建議禁用):
咱們能夠只查詢全部的 flight_number
:
或者更多的屬性:
是否是很簡單很神奇!
咱們也能夠經過傳入參數查詢單條信息:
const RootQuery = new GraphQLObjectType({ name: 'RootQueryType', fields: { ... launch: { type: LaunchType, args: { flight_number: { type: GraphQLInt } }, resolve(parent, args) { return axios.get(`https://api.spacexdata.com/v3/launches/${args.flight_number}`) .then(res => res.data); } } } });
結果:
剛剛咱們都是用GraphiQL在瀏覽器調用接口,接下來咱們看一下在前端頁面中怎麼調用graphql服務。前端咱們使用react。
在項目根目錄初始化react項目:
$ npx create-react-app client
爲了便於調試,在package.json
中增長scripts:
"start": "node server.js", "server": "nodemon server.js", "client": "npm start --prefix client", "dev":"concurrently \"npm run server\" \"npm run client\" "
樣式咱們使用bootswatch中的一款主題:
GraphQL的客戶端有多種實現,本次項目使用 Apollo,最流行的GraphQL Client。更多client請參考 GraphQL Clients。
安裝以下依賴:
$ cd client $ npm i apollo-boost react-apollo graphql
其中 apollo-boost
是apollo client自己,react-apollo
是react視圖層的集成,graphql
用於解析graphql的查詢語句。
修改App.js
內容以下:
import React, { Component } from 'react'; import ApolloClient from 'apollo-boost'; import { ApolloProvider } from 'react-apollo'; import './theme.css'; import './App.css'; import logo from './spacex-logo-light.png' const client = new ApolloClient({ uri: 'http://localhost:5000/graphql' }); class App extends Component { render() { return ( <ApolloProvider client={client}> <div className="container"> <img src={logo} id="logo" /> </div> </ApolloProvider> ); } } export default App;
和redux使用<Provider>
傳遞store相似,react-apollo
經過 <ApolloProvider>
將apollo client向下傳遞。
接着咱們來實現顯示launches的component,新增文件 components/Launches.js
:
import React, { Component, Fragment } from 'react'; import gql from 'graphql-tag'; import { Query } from 'react-apollo'; import LaunchItem from './LaunchItem'; const LAUNCHES_QUERY = gql` query LaunchesQuery { launches { flight_number, mission_name, launch_date_local,, launch_success, } } `; export class Launches extends Component { render() { return ( <Fragment> <h1 className="display-4 my-3">Launches</h1> <Query query={LAUNCHES_QUERY}> { ({ loading, error, data }) => { if (loading) return <h4>Loading...</h4> if (error) console.log(error); return ( <Fragment> { data.launches.map(launch => <LaunchItem key={launch.flight_number} launch={launch}/>) } </Fragment> ) } } </Query> </Fragment> ) } } export default Launches
query語句經過 graphql-tag
定義,傳入 <Query>
執行獲取數據並傳入 LaunchItem
顯示。
components/LaunchItem.js
:
import React from 'react' export default function LaunchItem({ launch: { flight_number, mission_name, launch_date_local, launch_success } }) { return ( <div className="card card-body mb-3"> <div className="col-md-9"> <h4>Mission: {mission_name}</h4> <p>Date: {launch_date_local,}</p> </div> <div className="col-md-3"> <button className="btn btn-secondary">Launch Details</button> </div> </div> ) }
查詢語句經過graphql-tag
定義,而後傳入<Query>
執行。
因爲本地調試,client和server分別運行在不一樣的端口,因此須要先進行跨域處理,使用 cors。
server.js
const cors = require('cors'); ... app.use(cors());
好了,大功告成,咱們來看一下效果:
今天就主要介紹GraphQL工程的搭建和GraphQL Query的使用,更多關於GraphQL的內容好比 Mutation下次有空會跟你們逐步講解。
本文靈感來源:Youtube@Traversy Media,感謝
本文Demo Github地址:Github@MudOnTire
本文Demo線上展現:Heroku@graphql-spacex-launches
最後,推薦你們使用 Fundebug,一款很好用的BUG監控工具~