React+GraphQL入门

最近刚完成一个新项目,闲着没事,想着学点新东西(做前端的人都懂,技术更新实在太快了,不学容易out),听说GraphQL现在开始火起来,大有取代传统Restful API的方式的趋势,所以我决定学学。

什么是 GraphQL

GraphQL 是由 Facebook 创造的用于 API 的查询语言(这里查询语言所指的并不是常规意义上的类似 sql 语句的查询语言,而是一种用于前后端数据查询方式的规范)。

GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
复制代码

更多关于GraphQL的介绍大家可以看这里

由于GraphQL只是一套规范,不能直接使用,但社区有了很多编程语言的实现,可以直接拿过来用。这里我选用了Apollo

什么是 Apollo

Apollo 是基于 GraphQL 的全栈解决方案集合。包括了 apollo-client 和 apollo-server ;从后端到前端提供了对应的 lib 使得开发使用 GraphQL 更加的方便。
复制代码

GraphQL需要前后端一起才能真正发挥它的的作用,我们先在服务端实现它,这里就要用到apollo-server

apollo-server是一个在Node.js上构建GraphQL服务端的web中间件。支持expresskoahapi等框架。这里我用的是koa

首先,我们要安装依赖包

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
复制代码

然后,编写代码

// 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));
复制代码

接下来,执行下面命令来让我们的服务端跑起来:

node server.js
app run in localhost:8090
复制代码

然后在浏览器里输入http://localhost:8090/graphiql,你会看到如下界面:

《React+GraphQL入门》 这时说明我们的
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,它包含下面这些字段:

《React+GraphQL入门》 其中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/结果发现页面报错,没能正常运行,我们打开开发者工具发现了其中一项报错:

《React+GraphQL入门》 从报错可以看出是跨域问题,因为项目是运行在两个不同的端口,因为浏览器的同源策略,所以不允许跨域访问。

那么如何才能实现跨域访问呢?我们需要在修改服务端代码让他支持跨域访问。

首先在服务端增加一个依赖包:

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,因为本人也是初学,很多东西也还在学习阶段。如果大家有什么好的开发心得,欢迎交流。

    原文作者:SQL
    原文地址: https://juejin.im/post/5b2da5e751882574dd4ad7d3
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞