React+GraphQL入門

最近剛完成一個新項目,閒着沒事,想着學點新東西(作前端的人都懂,技術更新實在太快了,不學容易out),據說GraphQL如今開始火起來,大有取代傳統Restful API的方式的趨勢,因此我決定學學。css

什麼是 GraphQL

GraphQL 是由 Facebook 創造的用於 API 的查詢語言(這裏查詢語言所指的並非常規意義上的相似 sql 語句的查詢語言,而是一種用於先後端數據查詢方式的規範)。

GraphQL 既是一種用於 API 的查詢語言也是一個知足你數據查詢的運行時。 GraphQL 對你的 API 中的數據提供了一套易於理解的完整描述,使得客戶端可以準確地得到它須要的數據,並且沒有任何冗餘,也讓 API 更容易地隨着時間推移而演進,還能用於構建強大的開發者工具。
複製代碼

更多關於GraphQL的介紹你們能夠看這裏前端

因爲GraphQL只是一套規範,不能直接使用,但社區有了不少編程語言的實現,能夠直接拿過來用。這裏我選用了Apollonode

什麼是 Apollo

Apollo 是基於 GraphQL 的全棧解決方案集合。包括了 apollo-client 和 apollo-server ;從後端到前端提供了對應的 lib 使得開發使用 GraphQL 更加的方便。
複製代碼

GraphQL須要先後端一塊兒才能真正發揮它的的做用,咱們先在服務端實現它,這裏就要用到apollo-serverreact

apollo-server是一個在Node.js上構建GraphQL服務端的web中間件。支持expresskoahapi等框架。這裏我用的是koaweb

首先,咱們要安裝依賴包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,你會看到以下界面: 編程

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組件會被注入一個名爲dataprops,它包含下面這些字段:

data
其中user和users是我查詢的字段,因此這兩個字段不是必須的。除此之外,其餘的都是必須的,其中 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/結果發現頁面報錯,沒能正常運行,咱們打開開發者工具發現了其中一項報錯:

error
從報錯能夠看出是跨域問題,由於項目是運行在兩個不一樣的端口,由於瀏覽器的同源策略,因此不容許跨域訪問。

那麼如何才能實現跨域訪問呢?咱們須要在修改服務端代碼讓他支持跨域訪問。

首先在服務端增長一個依賴包:

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,由於本人也是初學,不少東西也還在學習階段。若是你們有什麼好的開發心得,歡迎交流。

相關文章
相關標籤/搜索