【问题标题】:Wrapping a RESTapi with GraphQL using Apollo React使用 Apollo React 用 GraphQL 包装 REST api
【发布时间】:2018-03-19 02:20:00
【问题描述】:

我需要使用 Apollo 客户端和 React 做一个项目(货币兑换应用程序)。我需要用 graphql 包装现有的 REST api (fixer.io)。到目前为止,没有运气在网上找到解决方案。尝试了几个教程,但它们似乎不起作用。有人有这方面的经验吗?

谢谢。

【问题讨论】:

    标签: javascript rest graphql react-apollo


    【解决方案1】:

    我假设您使用 Apollo client 2.0 并希望一切都是客户端。

    首先你需要一个apollo bridge link。它用于“当您还没有 GraphQL 服务器并希望在客户端上使用 GraphQL 时”。它的源代码很短,所以你可以内联它:

    /*
      Copyright (c) 2017 David Cizek
      https://github.com/dacz/apollo-bridge-link
    */
    import { GraphQLSchema, graphql, print } from 'graphql';
    import { addMockFunctionsToSchema, makeExecutableSchema } from 'graphql-tools';
    
    import { ApolloLink } from 'apollo-link';
    import Observable from 'zen-observable';
    
    export const createBridgeLink = ({ schema, resolvers, mock, context = {} }) => {
        let executableSchema;
        if (typeof schema === 'string') {
            executableSchema = makeExecutableSchema({ typeDefs: schema, resolvers });
        } else if (schema.kind === 'Document') {
            executableSchema = makeExecutableSchema({
                typeDefs: print(schema),
                resolvers,
            });
        } else if (schema instanceof GraphQLSchema) {
            executableSchema = schema;
        } else {
            throw new Error('schema should be plain text, parsed schema or executable schema.');
        }
    
        if (mock)
            {addMockFunctionsToSchema({
                schema: executableSchema,
                preserveResolvers: true,
            });}
    
        return new ApolloLink(
            operation =>
                new Observable(observer => {
                    const { headers, credentials } = operation.getContext();
                    const ctx = {
                        ...context,
                        headers,
                        credentials,
                    };
    
                    graphql(executableSchema, print(operation.query), undefined, ctx, operation.variables, operation.operationName)
                        .then(data => {
                            observer.next(data);
                            observer.complete();
                        })
                        .catch(err => {
                            /* istanbul ignore next */
                            observer.error(err);
                        });
                }),
        );
    };
    
    export class BridgeLink extends ApolloLink {
        requester;
    
        constructor(opts) {
            super();
            this.requester = createBridgeLink(opts).request;
        }
    
        request(op) {
            return this.requester(op);
        }
    }
    

    接下来创建架构和解析器:

    // schema.js
    export default `
    type Rate {
      date: Date!
      rate: Float!
    }
    
    type Query {
      latestRate(from: String!, to: String!): Rate
    }
    
    schema {
      query: Query
    }
    `;
    
    
    // resolvers.js
    const resolvers = {
      Query: {
        latestRate(obj, args, context, info) {
          return fetch(`https://api.fixer.io/latest?base=${args.from}`).then(res => res.json())
          .then(res => { date: res.date, rate: res.rates[args.to] })
        }
      }
    }
    
    export default resolvers;
    

    最后,创建一个 apollo 客户端工厂:

    // clientFactory.js
    import { ApolloClient } from 'apollo-client';
    import { InMemoryCache } from 'apollo-cache-inmemory';
    
    import { BridgeLink } from './apollo-bridge-link';
    
    import schema from './schema';
    import resolvers from './resolvers';
    
    export default () => {
        const mock = false;
        const context = {};
    
        const client = new ApolloClient({
            link: new BridgeLink({ schema, resolvers, mock, context }),
            cache: new InMemoryCache(),
        });
        return client;
    };
    

    这是你如何使用它:

    import gql from 'graphql-tag';
    import clientFactory from './clientFactory'
    
    const client = clientFactory();
    
    client.query(gql`query {
      latestRate(from: "USD", to: "EUR") { date, rate }
    }`).then(console.log)
    

    如果你想在 React 中使用它:

    import { ApolloProvider } from 'react-apollo';
    const client = clientFactory();
    
    const App = ({ data: { latestRate, refetch } }) => {
      return <div>
        <span>Today:</span><span>{latestRate.date}</span>
        <span>1 USD equals:</span><span>{latestRate.rate} EUR</span>
        <button onClick={() => refetch()}>
          Refresh
        </button>
      </div>
    }
    
    const AppWithQuery = graphql(gql`
      query {
        latestRate(from: "USD", to: "EUR") { date, rate }
      }
    `)(App);
    
    ReactDOM.render(
      <ApolloProvider client={client}>
        <AppWithQuery/>
      </ApolloProvider>,
      document.getElementById('root'),
    );
    

    【讨论】:

      【解决方案2】:

      使用Graphcool Framework,您可以定义resolver functions,它允许您轻松封装任何REST API。您可以定义一个函数并将其连接到 GraphQL Schema 中的特定突变或查询。

      我准备好了a demo, wrapping the fixer API

      尝试运行此查询以获取以美元为基础的汇率,例如:

      query {
        fixer(
          base: "USD"
        ) {
          base
          date
          eur
          usd
          rub
        }
      }
      

      您可以像这样自己构建这个演示:

      git clone git@github.com:graphcool/templates.git
      cd templates/curated/misc/fixer-wrapper
      npm install -g graphcool@next
      graphcool init
      graphcool deploy
      graphcool playground
      

      请随时分享您可能想到的任何改进,例如open source。您可以阅读有关解析器的更多信息here

      【讨论】:

      猜你喜欢
      • 2021-11-23
      • 2020-07-04
      • 2020-01-21
      • 2017-09-01
      • 1970-01-01
      • 2020-11-08
      • 2019-01-27
      • 2021-05-02
      • 2018-01-28
      相关资源
      最近更新 更多