Apollo Multiple Clients with React?

在实际开发中,一个项目后端会拆分成几个微服务进行写,如:用户一个模块体系,订单一个模块体系,支付一个模块体系等,后端会提供不同二级域名的api接口。如果后端使用Graphql而不是使用Restful Api,这样我们就要考虑多个Apollo客户端。在实际项目中我也遇到这个问题了。今天我们翻译篇文章,关于REACT使用多个Apollo客户端,后续我也会把我最后完成的demo放出来,供大家参考。这篇文章来自于Medium上面,作者:Rafael Nunes,翻译文章原始地址

Apollo Multiple Clients with React?

React + Apollo Client + GraphQL = ❤

这篇文章快速解释了,如何在同一个React应用程序中使用不同的Apollo clients,但在最后,在使用多个GraphQL APIs时讨论了其他方法。这并不是有意要以任何方式去质疑GraphQL原理!

写这篇文章的原因是,作者发现自己遇到问题了,在React应用程序中怎么使用多clients查询不同GraphQL APIs。这表明Apollo GitHub项目中存在很多问题,讨论需求并提出实施建议。

TL;DR: passing any ApolloClient instance to Query/Mutation/Subscription components as props works just fine! Check: https://github.com/peaonunes/apollo-multiple-clients-example

下面列出了与相关问题、讨论和方案的一些链接。一些旧方案确实也已经合并,并且带有老的react-apollo版本。然而,从2.1版本开始Apollo客户端的使用和查询发生了许多变化(for better)。

  • https://github.com/apollographql/react-apollo/pull/481
  • https://github.com/apollographql/react-apollo/issues/464
  • https://github.com/apollographql/react-apollo/issues/1588
  • https://github.com/apollographql/react-apollo/pull/729

Why would we need multiple clients?

Apollo Client在初始化的时候只接受一个client uri。因此,就意味着同时只能使用一个client。

import ApolloClient from "apollo-boost";

const client = new ApolloClient({
 uri: "https://48p1r2roz4.sse.codesandbox.io"
});

例如,如果在React应用程序中需要从两个不同的GraphQL服务中获取数据,就不能使用相同的client或者程序实例了。

具体来说,我只是在找一个快速的实施方法从两个GraphQL APIs获取数据来验证解决方案。不必担心架构冲突,因类型、缓存、状态等等不会重叠。

在场景中,在Apollo上查询API时,有一种切换客户端的方法是有意义的。在当前方法中,使用ApolloProvider组件包裹你的整个应用程序,该组件通过上下文给应用程序传递实例化好的客户端。

import React from "react";
import { render } from "react-dom";

import { ApolloProvider } from "react-apollo";
import ApolloClient from "apollo-boost";

const client = new ApolloClient({
  uri: "https://w5xlvm3vzz.lp.gql.zone/graphql"
});

const App = () => (
  
    

My first Apollo app

); render(, document.getElementById("root"));

实际上使用Query Component使查询数据变得简单,但这也意味着,当查询时,客户端提供的上下文变量是唯一的。

作者花了一些时间查阅了大量问题和相关项目,结果发现有一种方法可以覆盖QueryMutation组件的客户端上下文,通过另一个客户端的props传递。


 {({ data }) => (
{data.name}
)}

Update, Aug 2019: Although they have changed the implementation it still works. https://github.com/apollographql/react-apollo/blob/master/packages/components/src/Query.tsx#L17

// https://github.com/apollographql/react-apollo/blob/master/src/Query.tsx#L167
// https://github.com/apollographql/react-apollo/blob/master/src/Mutation.tsx#L120
...
this.client = props.client || context.client;
...

官方文档并没有提及此功能。我们可以为组件传递任何client,这些client将优先通过props而不是context传递。下面案例:

// ...
const customClient = new ApolloClient({
  uri: "http://other-api/graphql"
});

const Dogs = ({ onDogSelected }) => (
  
    {({ loading, error, data }) => {
      if (loading) return "Loading...";
      if (error) return `Error! ${error.message}`;

      return (
        
      );
    }}
  
);
// ...

作者已经实现了一个可运行的示例,该示例使用了两个不同的clients,地址: https://github.com/peaonunes/apollo-multiple-clients-example

即使这个方法是有效的,也应该记住,除非同时传递两个clients的缓存,否则不会为两个clients同时运行Apollo功能(如果发生模式冲突,可能会有风险),单独管理其他功能。Apollo功能将会受到损害,并且随着应用程序的成长,代码库变得更冗余,开发将可能变得缓慢。

What would be the ideal approach then?

Solving the problem in the Frontend

本文讨论的结果,folks已经提出了一些解决方法,为解决这个问题他们做了自己的抽象/实现层。

Community own package implementations

Michael Duve写一个插件react-apollo-multiple-clients,用这个插件可以在多个clients之间转换。这个插件有多个提供者,它提供了一个高级组件(HOC),接收client prop,切换到使用者想要的client。进入里面讨论

Paul Grieselhuber,他建议了一种方法,所有的请求都是一个单client,选择一个uri方便的触发上下文,client就将请求分发出去。你可以在这里关注讨论。

Client-side schema stitching

尽管支持服务端,很少有人尝试在客户端上直接解决问题,在客户端上有一些问题正在寻找或请求联合,例如:#797

不过,Hasura公司给出了一个可行方案,关于客户端模式联合,在你的案例它可能已经足够了。

尽管作者认为这些方法可以解决这个问题,但是也认为随着应用程序增长,这些解决方法会增加前端程序的复杂性。我的观点,这个功能应该由后端来做,为所有的不同的APIs应提供统一的接口。

Gateways for Frontends

API网关是一种众所周知的模式,在我们的“微服务热潮”时代,采用频率越来越高。API网关是服务端和客户端之间的单个接口。

GraphQL开发中似乎已经达成共识,API网关是与不同GraphQL API进行连接的方式。然后有时网关会超越此范围,因为网关本身可以为其它REST和RPC API创建GraphQL 接口。

通过唯一网关提供不同APIs的真正问题是如何管理和编排不同的数据结构。

Client-side schema stitching

正如本文前面提到的,Apollo团队提倡的首次尝试是数据结构粘合。

  • The next generation of schema stitching
  • GraphQL Remote Stitching Micro-services with NodeJS

经过一段时间的发展,社区反馈这个方法是错弱的,现在已经被弃用了。

Apollo Federation

Apollo最近推出了一个新概念,叫做“Apollo Federation”,解决一个网关管理不同数据结构的问题。

“Apollo Federation is our answer for implementing GraphQL in a microservice architecture. It’s designed to replace schema stitching and solve pain points such as coordination, separation of concerns, and brittle gateway code.” James Baxley III

在这之前他们已经推出了Federation规范,在一些语言中已经实行了,例如:apollo-gateway。这个想法要有一个组成架构的网关,并且可以通过keys联合服务(就像主键),还能够扩展types。所有的这些仅仅用了GraphQL常规的规范。

建议花一些时间观看下面视频,并花一些时间尝试一下这种更好的方法。

视频

作者亲自尝试过,并且看到公司正在基于这种新方法开发解决方案。同样值得注意的是,还有其他挑战和空间,例如管理身份验证/授权,网关应具有的灵活性等其他讨论。希望Federation根据社区和公司的反馈而不断发展。

Conclusion

正如这篇文章之前提到的,它不是明确的给出多个GraphQL API的“正确”方法,是要指出希望解决当前这个问题的方法。

作者认为使用API网关和管理不同的GraphQL数据结构的整个讨论才刚刚开始,社区将致力于更完美更好的解决方案。

翻译结束

如翻译有问题请多谢指出!

这篇文章作者也提到了两个方案解决apollo multiple clients,一个是在单个query里面添加client,一个是通过网关的方式解决。在单个query里面添加client代码不是很优雅;后端确实也会做相应的网关,但不能解决全部问题,实际项目中还是需要解决。在下一篇文章我将介绍另一个方法使用Apollo multiple clients,这个也许是个更好的解决方案。

你可能感兴趣的:(Apollo Multiple Clients with React?)