graph-ql_REST API是REST-in-Peace API。 Graph QL万岁。

graph-ql

Update: This article is now part of my “Complete Introduction to GraphQL”.

更新:本文现在是我的“ GraphQL完整介绍”的一部分。

Read the updated version of this content and more about GraphQL at jscomplete.com/why-graphql.

jscomplete.com/why-graphql上阅读此内容的更新版本以及有关GraphQL的更多信息。

After years of dealing with REST APIs, when I first learned about GraphQL and the problems it’s attempting to solve, I could not resist tweeting the exact title of this article.

在使用REST API多年之后,当我第一次了解GraphQL及其要解决的问题时,我忍不住在推特上发布了本文的确切标题。

Of course, back then, it was just an attempt by me at being funny, but today I believe that the funny prediction is actually happening.

当然,那时候,我只是在做一个有趣的尝试,但是今天我相信有趣的预测实际上正在发生。

Please don’t interpret this wrong. I am not going to accuse GraphQL of “killing” REST or anything like that. REST will probably never die, just like XML never did. I simply think GraphQL will do to REST what JSON did to XML.

请不要误解。 我不会指责GraphQL“杀死” REST或类似的东西。 REST可能永远不会消失,就像XML永远不会消失一样。 我只是认为GraphQL将对REST起作用,就像JSON对XML所做的那样。

This article is not actually 100% in favor of GraphQL. There is a very important section about the cost of GraphQL’s flexibility. With great flexibility comes great cost.

本文实际上并不是100%支持GraphQL。 关于GraphQL灵活性的成本,有一个非常重要的部分。 灵活性高,成本高。

I am a big fan of “Always Start with WHY”, so let’s do that.

我是“始终从WHY开始 ”的忠实拥护者 ,所以让我们开始吧。

简介:为什么选择GraphQL? (In Summary: Why GraphQL?)

The 3 most important problems that GraphQL solves beautifully are:

GraphQL解决的3个最重要的问题是:

  • The need to do multiple round trips to fetch data required by a view: With GraphQL, you can always fetch all the initial data required by a view with a single round-trip to the server. To do the same with a REST API, we need to introduce unstructured parameters and conditions that are hard to manage and scale.

    需要做多次往返获取由视图所需的数据 :随着GraphQL,你可以随时取用一个往返到服务器的视图所需的所有初始数据。 要使用REST API进行同样的操作,我们需要引入难以管理和扩展的非结构化参数和条件。

  • Clients dependency on servers: With GraphQL, the client speaks a request language which: 1) eliminates the need for the server to hardcode the shape or size of the data, and 2) decouples clients from servers. This means we can maintain and improve clients separately from servers.

    客户端对服务器的依赖 :借助GraphQL,客户端可以说出一种请求语言:1)不需要服务器对数据的形状或大小进行硬编码,并且2)将客户端与服务器分离。 这意味着我们可以与服务器分开维护和改进客户端。

  • The bad front-end developer experience: With GraphQL, developers express the data requirements of their user interfaces using a declarative language. They express what they need, not how to make it available. There is a tight relationship between what data is needed by the UI and the way a developer can express a description of that data in GraphQL .

    糟糕的前端开发人员体验 :使用GraphQL,开发人员可以使用声明性语言来表达其用户界面的数据要求。 他们表示,他们需要什么 ,而不是如何使其可用。 UI需要哪些数据与开发人员可以在GraphQL中表达该数据的描述之间存在紧密的关系。

This article will explain in detail how GraphQL solves all these problems.

本文将详细解释GraphQL如何解决所有这些问题。

Before we begin, for those of you not yet acquainted with GraphQL, let’s start with simple definitions.

在开始之前,对于尚未熟悉GraphQL的人,让我们从简单的定义开始。

什么是GraphQL? (What is GraphQL?)

GraphQL is a language. If we teach GraphQL to a software application, that application will be able to declaratively communicate any data requirements to a backend data service that also speaks GraphQL.

GraphQL是一种语言 。 如果我们将GraphQL教给一个软件应用程序,则该应用程序将能够声明性地将任何数据要求传达给也讲GraphQL的后端数据服务。

Just like a child can quickly learn a new language — while a grown-up will have a harder time picking it up — starting a new application from scratch using GraphQL will be a lot easier than introducing GraphQL to a mature application.
就像孩子可以快速学习一门新语言一样-尽管成年人将很难学习它-与使用GraphQL引入成熟的应用程序相比,使用GraphQL从头开始新的应用程序要容易得多。

To teach a data service to speak GraphQL, we need to implement a runtime layer and expose it to the clients who want to communicate with the service. Think of this layer on the server side as simply a translator of the GraphQL language, or a GraphQL-speaking agent who represents the data service. GraphQL is not a storage engine, so it can’t be a solution on its own. This is why we can’t have a server that speaks just GraphQL and we need to implement a translating runtime instead.

要教数据服务说GraphQL,我们需要实现一个运行时层,并将其公开给想要与该服务进行通信的客户端。 可以将服务器端的这一层看作是GraphQL语言的翻译器,或者是代表数据服务的GraphQL语言代理。 GraphQL不是存储引擎,因此它本身不是解决方案。 这就是为什么我们不能拥有只讲GraphQL的服务器,而我们需要实现翻译运行时的原因。

This layer, which can be written in any language, defines a generic graph-based schema to publish the capabilities of the data service it represents. Client applications who speak GraphQL can query that schema within its capabilities. This approach decouples clients from servers and allows both of them to evolve and scale independently.

该层可以用任何语言编写,它定义了一个基于图形的通​​用架构,以发布其表示的数据服务的功能 。 使用GraphQL的客户端应用程序可以在其功能范围内查询该架构。 这种方法使客户端与服务器脱钩,并允许它们两者独立发展和扩展。

A GraphQL request can be either a query (read operation) or a mutation (write operation). For both cases, the request is a simple string that a GraphQL service can interpret, execute, and resolve with data in a specified format. The popular response format that is usually used for mobile and web applications is JSON.

GraphQL请求可以是查询 (读取操作)或变异 (写入操作)。 对于这两种情况,请求都是一个简单的字符串,GraphQL服务可以使用指定格式的数据解释,执行和解析该字符串。 通常用于移动和Web应用程序的流行响应格式是JSON

什么是GraphQL? (像我一样解释5版本) (What is GraphQL? (The Explain-it-like-I’m-5 version))

GraphQL is all about data communication. You have a client and a server and both of them need to talk with each other. The client needs to tell the server what data it needs, and the server needs to fulfill this client’s data requirement with actual data. GraphQL steps into the middle of this communication.

GraphQL与数据通信有关。 您有一个客户端和一个服务器,并且两者都需要互相交谈。 客户端需要告诉服务器它需要什么数据,并且服务器需要用实际数据满足该客户端的数据要求。 GraphQL进入了此通信的中间。

Why can’t the client just communicate directly with the server, you ask? It sure can.

您问为什么客户不能直接与服务器通信? 当然可以。

There are a few reasons to consider a GraphQL layer between clients and servers. One of those reasons, and perhaps the most popular one, is efficiency. The client usually needs to ask the server about multiple resources, and the server usually understands how to reply with a single resource. So the client ends up doing multiple round-trips to the server to gather all the data it needs.

在客户端和服务器之间考虑GraphQL层有几个原因。 这些原因之一,也许是最受欢迎的原因,就是效率 。 客户端通常需要向服务器询问多个资源,并且服务器通常了解如何使用单个资源进行回复。 因此,客户端最终将多次往返服务器,以收集其所需的所有数据。

With GraphQL, we can basically shift this multi-request complexity to the server-side and have the GraphQL layer deal with it. The client asks the GraphQL layer a single question and gets a single response that has exactly what the client needs.

使用GraphQL,我们基本上可以将这种多请求复杂性转移到服务器端,并让GraphQL层处理它。 客户向GraphQL层提出一个问题,并获得一个具有客户确切需求的响应。

There are a lot more benefits to using a GraphQL layer. For example, one other big benefit is communicating with multiple services. When you have multiple clients requesting data from multiple services, a GraphQL layer in the middle can simplify and standardize this communication. Although this is not really a point against REST APIs — as it is easy to accomplish the same there — a GraphQL runtime offers a structured and standardized way of doing it.

使用GraphQL层还有很多好处。 例如,另一大好处是与多种服务进行通信。 当有多个客户端从多个服务请求数据时,中间的GraphQL层可以简化并标准化这种通信。 尽管这并不是针对REST API的真正意义(因为在此很容易做到这一点),但GraphQL运行时提供了一种结构化和标准化的方式。

Instead of a client going to the two different data services directly (in the slide above), we can have that client communicate with the GraphQL layer. Then the GraphQL layer will do the communication with the two different data services. This is how GraphQL first isolates the clients from needing to communicate in multiple languages and also translates a single request into multiple requests to multiple services using different languages.

代替客户端直接访问两个不同的数据服务(在上面的幻灯片中),我们可以让该客户端与GraphQL层进行通信。 然后GraphQL层将与两个不同的数据服务进行通信。 这就是GraphQL首先隔离客户端以使其无需使用多种语言进行通信的方式,还可以将单个请求转换为使用不同语言对多个服务的多个请求。

Imagine that you have three people who speak three different languages and have different types of knowledge. Then imagine that you have a question that can only be answered by combining the knowledge of all three people together. If you have a translator who speaks all three languages, the task of putting together an answer to your question becomes easy. This is exactly what a GraphQL runtime does.
想象一下,您有三个人会说三种不同的语言,并且拥有不同类型的知识。 然后想象您有一个问题,只有将所有三个人的知识结合在一起才能回答。 如果您有会说三种语言的翻译员,那么将问题的答案汇总在一起的任务就很容易了。 这正是GraphQL运行时所做的。

Computers aren’t smart enough to answer just any questions (at least not yet), so they have to follow an algorithm somewhere. This is why we need to define a schema on the GraphQL runtime and that schema gets used by the clients.

计算机还不够智能,无法回答任何问题(至少尚未回答),因此它们必须在某个地方遵循算法。 这就是为什么我们需要在GraphQL运行时上定义一个架构,并且该架构被客户端使用的原因。

The schema is basically a capabilities document that has a list of all the questions which the client can ask the GraphQL layer. There is some flexibility in how to use the schema because we’re talking about a graph of nodes here. The schema mostly represents the limits of what can be answered by the GraphQL layer.

该架构基本上是一个功能文档,其中包含客户端可以向GraphQL层提出的所有问题的列表。 在使用模式方面有一定的灵活性,因为我们在这里谈论的是节点图。 该方案主要表示GraphQL层可以回答的限制。

Still not clear? Let’s call GraphQL what it really and simply is: A replacement for REST APIs. So let me answer the question that you’re most likely asking now.

还是不清楚? 让我们将GraphQL称为真正的简单的东西: REST API的替代品。 因此,让我回答您最有可能问的问题。

REST API有什么问题? (What’s wrong with REST APIs?)

The biggest problem with REST APIs is the nature of multiple endpoints. These require clients to do multiple round-trips to get their data.

REST API的最大问题是多个端点的性质。 这些要求客户端进行多次往返以获取其数据。

REST APIs are usually a collection of endpoints, where each endpoint represents a resource. So when a client needs data from multiple resources, it needs to perform multiple round-trips to a REST API to put together the data it needs.

REST API通常是端点的集合,其中每个端点代表一个资源。 因此,当客户端需要来自多个资源的数据时,它需要对REST API执行多次往返以将其所需的数据汇总在一起。

In a REST API, there is no client request language. Clients do not have control over what data the server will return. There is no language through which they can do so. More accurately, the language available for clients is very limited.

在REST API中,没有客户端请求语言。 客户端无法控制服务器将返回什么数据。 他们没有语言可以做到这一点。 更准确地说,可供客户使用的语言非常有限。

For example, the READ REST API endpoints are either:

例如, READ REST API端点是:

  • GET /ResourceName - to get a list of all the records from that resource, or

    GET /ResourceName从该资源获取所有记录的列表,或者

  • GET /ResourceName/ResourceID - to get the single record identified by that ID.

    GET /ResourceName/ResourceID获取由该ID标识的单个记录。

A client can’t, for example, specify which fields to select for a record in that resource. That information is in the REST API service itself and the REST API service will always return all of the fields regardless of which ones the client actually needs. GraphQL’s term for this problem is over-fetching of information that’s not needed. It’s a waste of network and memory resources for both the client and server.

例如,客户端无法指定要为该资源中的记录选择的字段 。 该信息在REST API服务本身中,并且REST API服务将始终返回所有字段,而不管客户端实际需要哪个字段。 GraphQL解决此问题的术语是过度获取不需要的信息。 客户端和服务器都浪费了网络和内存资源。

One other big problem with REST APIs is versioning. If you need to support multiple versions, that usually means new endpoints. This leads to more problems while using and maintaining those endpoints and it might be the cause of code duplication on the server.

REST API的另一个大问题是版本控制。 如果需要支持多个版本,则通常意味着新的端点。 这会在使用和维护这些端点时导致更多问题,并且可能是服务器上代码重复的原因。

The REST APIs problems mentioned above are the ones specific to what GraphQL is trying to solve. They are certainly not all of the problems of REST APIs, and I don’t want to get into what a REST API is and is not. I am mostly talking about the popular resource-based-HTTP-endpoint APIs. Every one of those APIs eventually turns into a mix that has regular REST endpoints + custom ad-hoc endpoints crafted for performance reasons. This is where GraphQL offers a much better alternative.

上面提到的REST API问题是GraphQL试图解决的特定问题。 它们当然不是REST API的全部问题,我也不想深入了解REST API的本质。 我主要是在谈论流行的基于资源的HTTP端点API。 这些API中的每一个最终都会变成一种混合,这些混合具有常规的REST端点+出于性能原因而定制的自定义临时端点。 这是GraphQL提供更好的替代方案的地方。

GraphQL如何发挥其魔力? (How does GraphQL do its magic?)

There are a lot of concepts and design decisions behind GraphQL, but probably the most important ones are:

GraphQL背后有很多概念和设计决策,但最重要的可能是:

  • A GraphQL schema is a strongly typed schema. To create a GraphQL schema, we define fields that have types. Those types can be primitive or custom and everything else in the schema requires a type. This rich type system allows for rich features like having an introspective API and being able to build powerful tools for both clients and servers.

    GraphQL模式是强类型模式。 要创建GraphQL模式,我们定义具有类型的 字段 。 这些类型可以是原始类型或自定义类型,架构中的所有其他内容都需要类型。 这种丰富类型的系统具有丰富的功能,例如具有自省的API以及能够为客户端和服务器构建强大的工具。

  • GraphQL speaks to the data as a Graph, and data is naturally a graph. If you need to represent any data, the right structure is a graph. The GraphQL runtime allows us to represent our data with a graph API that matches the natural graph shape of that data.

    GraphQL将数据称为图,而数据自然是图。 如果需要表示任何数据,则正确的结构是图形。 GraphQL运行时允许我们使用与该数据的自然图形形状匹配的图形API表示数据。
  • GraphQL has a declarative nature for expressing data requirements. GraphQL provides clients with a declarative language for them to express their data needs. This declarative nature creates a mental model around using the GraphQL language that’s close to the way we think about data requirements in English and it makes working with a GraphQL API a lot easier than the alternatives.

    GraphQL具有表示数据需求的声明性。 GraphQL为客户提供一种声明性语言来表达他们的数据需求。 这种声明性的性质围绕着使用GraphQL语言创建了一种思维模型,该模型与我们对英语中的数据需求的思考方式非常接近,并且使GraphQL API的使用比其他方法容易得多。

The last concept is why I personally believe GraphQL is a game changer.

最后一个概念是为什么我个人认为GraphQL会改变游戏规则。

Those are all high-level concepts. Let’s get into some more details.

这些都是高级概念。 让我们进一步了解一些细节。

To solve the multiple round-trip problem, GraphQL makes the responding server just a single endpoint. Basically, GraphQL takes the custom endpoint idea to an extreme and just makes the whole server a single custom endpoint that can reply to all data questions.

为了解决多次往返问题,GraphQL使响应服务器只是一个端点。 基本上,GraphQL将定制端点的想法发挥到了极致,并且使整个服务器成为可以回答所有数据问题的单个定制端点。

The other big concept that goes with this single endpoint concept is the rich client request language that is needed to work with that custom single endpoint. Without a client request language, a single endpoint is useless. It needs a language to process a custom request and respond with data for that custom request.

此单一端点概念附带的另一个重要概念是使用该自定义单一端点所需的富客户端请求语言。 没有客户端请求语言,单个端点是无用的。 它需要一种语言来处理自定义请求并使用该自定义请求的数据进行响应。

Having a client request language means that the clients will be in control. They can ask for exactly what they need and the server will reply with exactly what that they’re asking for. This solves the over-fetching problem.

使用客户请求语言意味着客户将受到控制。 他们可以确切地要求他们所需要的,服务器将准确地答复他们所要的。 这解决了过度获取问题。

When it comes to versioning, GraphQL has an interesting take on that. Versioning can be avoided all together. Basically, we can just add new fields without removing the old ones, because we have a graph and we can flexibly grow the graph by adding more nodes. So we can leave paths on the graph for old APIs and introduce new ones without labeling them as new versions. The API just grows.

关于版本控制,GraphQL对此很有意思。 可以一起避免版本控制。 基本上,我们可以添加新字段而不删除旧字段 ,因为我们有一个图,并且可以通过添加更多节点来灵活地增长图。 因此,我们可以在图表上为旧的API保留路径,并引入新的API,而无需将其标记为新版本。 API不断增长。

This is especially important for mobile clients because we can’t control the version of the API they’re using. Once installed, a mobile app might continue to use that same old version of the API for years. On the web, it’s easy to control the version of the API because we just push new code. For mobile apps, that’s a lot harder to do.

这对于移动客户端特别重要,因为我们无法控制他们使用的API版本。 安装后,移动应用程序可能会继续使用该API的旧版本多年。 在网络上,控制API的版本很容易,因为我们只是推送新代码。 对于移动应用程序,这很难完成。

Not totally convinced yet? How about we do a one-to-one comparison between GraphQL and REST with an actual example?

还没有完全说服? 我们如何通过实际示例在GraphQL和REST之间进行一对一比较?

RESTful API与GraphQL API —示例 (RESTful APIs vs GraphQL APIs — Example)

Let’s imagine that we are the developers responsible for building a shiny new user interface to represent the Star Wars films and characters.

让我们想象一下,我们是负责构建闪亮的新用户界面来表示《星球大战》电影和角色的开发人员。

The first UI we’ve been tasked to build is simple: a view to show information about a single Star Wars person. For example, Darth Vader, and all the films this person appeared in. This view should display the person’s name, birth year, planet name, and the titles of all the films in which they appeared.

我们负责构建的第一个UI很简单:显示有关单个《星球大战》人物信息的视图。 例如,达斯·维达(Darth Vader)以及此人出现的所有电影。此视图应显示该人的名字,出生年月,星球的名字以及出现的所有电影的标题。

As simple as that sounds, we’re actually dealing with 3 different resources here: Person, Planet, and Film. The relationship between these resources is simple and anyone can guess the shape of the data here. A person object belongs to one planet object and it will have one or more films objects.

听起来很简单,实际上我们在这里处理3种不同的资源:人物,星球和电影。 这些资源之间的关系很简单,任何人都可以在这里猜测数据的形状。 一个人对象属于一个行星对象,它将有一个或多个电影对象。

The JSON data for this UI could be something like:

此UI的JSON数据可能类似于:

{
   "data":{
      "person":{
         "name":"Darth Vader",
         "birthYear":"41.9BBY",
         "planet":{
            "name":"Tatooine"
         },
         "films":[
            {
               "title":"A New Hope"
            },
            {
               "title":"The Empire Strikes Back"
            },
            {
               "title":"Return of the Jedi"
            },
            {
               "title":"Revenge of the Sith"
            }
         ]
      }
   }
}

Assuming a data service gave us this exact structure for the data, here’s one possible way to represent its view with React.js:

假设数据服务为我们提供了这种确切的数据结构,这是使用React.js表示其视图的一种可能方法:

// The Container Component:<PersonProfile person={data.person} ></PersonProfile>
// The PersonProfile Component:Name: {person.name}Birth Year: {person.birthYear}Planet: {person.planet.name}Films: {person.films.map(film => film.title)}

This is a simple example, and while our experience with Star Wars might have helped us here a bit, the relationship between the UI and the data is very clear. The UI used all the “keys” from the JSON data object we imagined.

这是一个简单的示例,尽管我们在《星球大战》方面的经验可能在这里有所帮助,但UI和数据之间的关系非常清楚。 UI使用了我们想象中的JSON数据对象中的所有“键”。

Let’s now see how we can ask for this data using a RESTful API.

现在让我们看看如何使用RESTful API来请求这些数据。

We need a single person’s information, and assuming that we know the ID of that person, a RESTful API is expected to expose that information as:

我们需要一个人的信息,并且假设我们知道该人的ID,那么RESTful API可以将该信息公开为:

GET - /people/{id}

This request will give us the name, birthYear, and other information about the person. A good RESTful API will also give us the ID of this person’s planet and an array of IDs for all the films this person appeared in.

该请求将为我们提供姓名,生日和其他有关此人的信息。 良好的RESTful API还将为我们提供此人的星球的ID,以及该人出演的所有电影的ID数组。

The JSON response for this request could be something like:

此请求的JSON响应可能类似于:

{  "name": "Darth Vader",  "birthYear": "41.9BBY",  "planetId": 1  "filmIds": [1, 2, 3, 6],  *** other information we do not need ***}

Then to read the planet’s name, we ask:

然后,要读取地球的名称,我们会问:

GET - /planets/1

And to read the films titles, we ask:

为了阅读电影标题,我们要求:

GET - /films/1GET - /films/2GET - /films/3GET - /films/6

Once we have all 6 responses from the server, we can combine them to satisfy the data needed by our view.

一旦从服务器获得所有6个响应,就可以将它们组合起来以满足视图所需的数据。

Besides the fact that we had to do 6 round-trips to satisfy a simple data need for a simple UI, our approach here was imperative. We gave instructions for how to fetch the data and how to process it to make it ready for the view.

除了必须进行6次往返来满足简单UI的简单数据需求这一事实外,我们在这里的方法势在必行。 我们提供了有关如何获取数据以及如何对其进行处理以使其准备用于视图的说明。

You can try this yourself if you want to see what I mean. The Star Wars data has a RESTful API currently hosted at http://swapi.co/. Go ahead and try to construct our data person object there. The keys might be a bit different, but the API endpoints will be the same. You will need to do exactly 6 API calls. Furthermore, you will have to over-fetch information that the view does not need.

如果您想了解我的意思,可以自己尝试。 《星球大战》数据具有RESTful API,目前托管在http://swapi.co/上 。 继续尝试在此处构造我们的数据人对象。 密钥可能有所不同,但是API端点将相同。 您将需要执行6个API调用。 此外,您将不得不过度获取视图不需要的信息。

Of course, this is just one implementation of a RESTful API for this data. There could be better implementations that will make this view easier to implement. For example, if the API server implemented nested resources and understood the relationship between a person and a film, we could read the films data with:

当然,这只是此数据的RESTful API的一种实现。 可能会有更好的实现,使该视图更易于实现。 例如,如果API服务器实现了嵌套资源并了解人与电影之间的关系,我们可以通过以下方式读取电影数据:

GET - /people/{id}/films

However, a pure RESTful API server would most likely not implement that, and we would need to ask our backend engineers to create this custom endpoint for us. That’s the reality of scaling a RESTful API — we just add custom endpoints to efficiently satisfy the growing clients needs. Managing custom endpoints like these is hard.

但是,纯RESTful API服务器很可能不会实现该功能,我们需要请后端工程师为我们创建此自定义端点。 这就是扩展RESTful API的现实-我们只需添加自定义端点即可有效满足不断增长的客户端需求。 管理这样的自定义端点很困难。

Let’s now look at the GraphQL approach. GraphQL on the server embraces the custom endpoints idea and takes it to its extreme. The server will be just a single endpoint and the channel does not matter. If we’re doing this over HTTP, the HTTP method certainly wouldn’t matter either. Let’s assume we have a single GraphQL endpoint exposed over HTTP at /graphql.

现在让我们看一下GraphQL方法。 服务器上的GraphQL包含自定义终结点概念,并将其发挥到了极致。 服务器将只是单个端点,并且通道无关紧要。 如果我们通过HTTP进行此操作,那么HTTP方法当然也没有关系。 假设我们在/graphql通过HTTP公开了一个GraphQL端点。

Since we want to ask for the data we need in a single round-trip, we’ll need a way to express our complete data needs for the server. We do this with a GraphQL query:

由于我们想在一次往返中查询所需的数据,因此我们需要一种表达服务器完整数据需求的方法。 我们使用GraphQL查询来做到这一点:

GET or POST - /graphql?query={...}

A GraphQL query is just a string, but it will have to include all the pieces of the data that we need. This is where the declarative power comes in.

GraphQL查询只是一个字符串,但它必须包含我们需要的所有数据。 这就是声明能力的体现。

In English, here’s how we declare our data requirement: we need a person’s name, birth year, planet’s name, and the titles of all their films. In GraphQL, this translates to:

用英语,这是我们声明数据要求的方式: 我们需要一个人的名字,出生年月,星球的名字以及所有电影的片名 。 在GraphQL中,这转换为:

{  person(ID: ...) {    name,    birthYear,    planet {      name    },    films {      title    }  }}

Read the English-expressed requirements one more time and compare it to the GraphQL query. It’s as close as it can get. Now, compare this GraphQL query with the original JSON data that we started with. The GraphQL query is the exact structure of the JSON data, except without all the “values” parts. If we think of this in terms of a question-answer relation, the question is the answer statement without the answer part.

再次阅读英语表达的要求,并将其与GraphQL查询进行比较。 它尽可能接近。 现在,将这个GraphQL查询与我们开始使用的原始JSON数据进行比较。 GraphQL查询是JSON数据的确切结构,但没有所有“值”部分。 如果我们从问题-答案关系的角度考虑问题,那么问题就是没有答案部分的答案陈述。

If the answer statement is:

如果答案为:

The closest planet to the Sun is Mercury.

离太阳最近的行星是水星。

A good representation of the question is the same statement without the answer part:

问题的一个很好的表示是没有答案部分的相同陈述:

(What is) the closest planet to the Sun?

(什么是)离太阳最近的行星?

The same relationship applies to a GraphQL query. Take a JSON response, remove all the “answer” parts (which are the values), and you end up with a GraphQL query very suitable to represent a question about that JSON response.

相同的关系适用于GraphQL查询。 进行JSON响应,删除所有“答案”部分(即值),最后得到一个GraphQL查询,非常适合表示有关该JSON响应的问题。

Now, compare the GraphQL query with the declarative React UI we defined for the data. Everything in the GraphQL query is used in the UI, and everything used in the UI appears in the GraphQL query.

现在,将GraphQL查询与我们为数据定义的声明性React UI进行比较。 UI中使用了GraphQL查询中的所有内容,UI中使用了UI中使用的所有内容。

This is the great mental model of GraphQL. The UI knows the exact data it needs and extracting that requirement is fairly easy. Coming up with a GraphQL query is simply the task of extracting what’s used as variables directly from the UI.

这是GraphQL的出色思维模型。 UI知道需要的确切数据,提取该需求非常容易。 提出GraphQL查询只是直接从UI中提取用作变量的内容的任务。

If we invert this model, it would still hold the power. If we have a GraphQL query, we know exactly how to use its response in the UI because the query will be the same “structure” as the response. We don’t need to inspect the response to know how to use it and we don’t need any documentation about the API. It’s all built-in.

如果我们颠倒这个模型,它仍将保持力量。 如果我们有一个GraphQL查询,我们将确切知道如何在UI中使用它的响应,因为查询将与响应具有相同的“结构”。 我们不需要检查响应就知道如何使用它,也不需要任何有关API的文档。 全部内置。

Star Wars data has a GraphQL API hosted at https://github.com/graphql/swapi-graphql. Go ahead and try to construct our data person object there. There are a few minor differences that we’ll explain later, but here’s the official query you can use against this API to read our data requirement for the view (with Darth Vader as an example):

《星球大战》数据有一个GraphQL API,托管在https://github.com/graphql/swapi-graphql上 。 继续尝试在此处构造我们的数据人对象。 我们将在后面解释一些细微的差异,但这是您可以针对此API使用的正式查询,以读取我们对该视图的数据要求(以Darth Vader为例):

{  person(personID: 4) {    name,    birthYear,    homeworld {      name    },    filmConnection {      films {        title      }    }  }}

This request gives us a response structure very close to what our view used, and remember, we’re getting all of this data in a single round-trip.

该请求使我们的响应结构非常接近于我们的视图所使用的结构,请记住,我们是在一次往返中获取所有这些数据的。

GraphQL灵活性的代价 (The Cost of GraphQL’s Flexibility)

Perfect solutions are fairy tales. With the flexibility GraphQL introduces, a door opens on some clear problems and concerns.

完美的解决方案就是童话。 GraphQL引入的灵活性为一些明显的问题和疑虑打开了一扇门。

One important threat that GraphQL makes easier is resource exhaustion attacks (AKA Denial of Service attacks). A GraphQL server can be attacked with overly complex queries that will consume all the resources of the server. It’s very simple to query for deep nested relationships (user -> friends -> friends …), or use field aliases to ask for the same field many times. Resource exhaustion attacks are not specific to GraphQL, but when working with GraphQL we have to be extra careful about them.

GraphQL简化的一个重要威胁是资源耗尽攻击(又称为拒绝服务攻击)。 GraphQL服务器可能会受到过于复杂的查询攻击,这些查询将消耗服务器的所有资源。 查询深层嵌套的关系(用户->朋友->朋友…)非常简单,或者使用字段别名多次请求相同的字段非常简单。 资源耗尽攻击并非特定于GraphQL,但是在使用GraphQL时,我们必须格外小心。

There are some mitigations we can do here. We can do cost analysis on the query in advance and enforce some kind of limits on the amount of data one can consume. We can also implement a time-out to kill requests that take too long to resolve. Also, since GraphQL is just a resolving layer, we can handle the rate limits enforcement at a lower level under GraphQL.

我们可以在这里采取一些缓解措施。 我们可以预先对查询进行成本分析,并对可以消耗的数据量实施某种限制。 我们还可以实现超时,以杀死需要太长时间才能解决的请求。 另外,由于GraphQL只是一个解析层,因此我们可以在GraphQL下以较低级别处理速率限制实施。

If the GraphQL API endpoint we’re trying to protect is not public and is meant for internal consumption of our own clients (web or mobile), we can use a whitelist approach and pre-approve queries that the server can execute. Clients can just ask the servers to execute pre-approved queries using a query unique identifier. Facebook seems to be using this approach.

如果我们要保护的GraphQL API端点不是公开的,并且是供我们自己的客户端(网络或移动客户端)内部使用的,则我们可以使用白名单方法并预先批准服务器可以执行的查询。 客户端可以使用查询唯一标识符要求服务器执行预先批准的查询。 Facebook似乎正在使用这种方法。

Authentication and authorization are other concerns that we need to think about when working with GraphQL. Do we handle them before, after, or during a GraphQL resolve process?

身份验证和授权是使用GraphQL时需要考虑的其他问题。 我们在GraphQL解析过程之前,之后或期间处理它们吗?

To answer this question, think of GraphQL as a DSL (domain specific language) on top of your own backend data fetching logic. It’s just one layer that we could put between the clients and our actual data service (or multiple services).

要回答此问题,请在您自己的后端数据获取逻辑之上将GraphQL视为DSL(特定于域的语言)。 这只是我们可以在客户端和实际数据服务(或多个服务)之间放置的一层。

Think of authentication and authorization as another layer. GraphQL will not help with the actual implementation of the authentication or authorization logic. It’s not meant for that. But if we want to put these layers behind GraphQL, we can use GraphQL to communicate the access tokens between the clients and the enforcing logic. This is very similar to the way we do authentication and authorization with RESTful APIs.

将身份验证和授权视为另一层。 GraphQL不会对身份验证或授权逻辑的实际实现有所帮助。 这不是为了那个。 但是,如果要将这些层放在GraphQL后面,则可以使用GraphQL在客户端和执行逻辑之间传递访问令牌。 这与我们使用RESTful API进行身份验证和授权的方式非常相似。

One other task that GraphQL makes a bit more challenging is client data caching. RESTful APIs are easier to cache because of their dictionary nature. This location gives that data. We can use the location itself as the cache key.

GraphQL带来的另一项挑战是客户端数据缓存。 RESTful API由于其字典性质而更易于缓存。 此位置提供该数据。 我们可以使用位置本身作为缓存键。

With GraphQL, we can adopt a similar basic approach and use the query text as a key to cache its response. But this approach is limited, not very efficient, and can cause problems with data consistency. The results of multiple GraphQL queries can easily overlap, and this basic caching approach would not account for the overlap.

使用GraphQL,我们可以采用类似的基本方法,并将查询文本用作存储其响应的键。 但是这种方法是有限的,不是很有效,并且可能导致数据一致性问题。 多个GraphQL查询的结果很容易重叠,并且这种基本的缓存方法无法解决重叠问题。

There is a brilliant solution to this problem though. A Graph Query means a Graph Cache. If we normalize a GraphQL query response into a flat collection of records, giving each record a global unique ID, we can cache those records instead of caching the full responses.

但是,对于这个问题有一个绝妙的解决方案。 图查询表示图缓存 。 如果我们将GraphQL查询响应规范化为平坦的记录集合,并为每个记录赋予全局唯一ID,则可以缓存这些记录,而不是缓存完整的响应。

This is not a simple process though. There will be records referencing other records and we will be managing a cyclic graph there. Populating and reading the cache will need query traversal. We need to code a layer to handle the cache logic. But this method will overall be a lot more efficient than response-based caching. Relay.js is one framework that adopts this caching strategy and auto-manages it internally.

但是,这不是一个简单的过程。 会有记录引用其他记录,我们将在那里管理一个循环图。 填充和读取缓存将需要遍历查询。 我们需要编写一层代码来处理缓存逻辑。 但是,与基于响应的缓存相比,该方法总体上效率更高。 Relay.js是一个采用这种缓存策略并在内部自动管理它的框架。

Possibly the most important problem that we should be concerned about with GraphQL is the problem that’s commonly referred to as N+1 SQL queries. GraphQL query fields are designed to be stand-alone functions and resolving those fields with data from a database might result in a new database request per resolved field.

也许我们应该用GraphQL关注的最重要的问题是通常称为N + 1 SQL查询的问题。 GraphQL查询字段被设计为独立功能,并且使用数据库中的数据解析这些字段可能会导致每个已解析字段提出新的数据库请求。

For a simple RESTful API endpoint logic, it’s easy to analyze, detect, and solve N+1 issues by enhancing the constructed SQL queries. For GraphQL dynamically resolved fields, it’s not that simple. Luckily Facebook is pioneering one possible solution to this problem: DataLoader.

对于简单的RESTful API端点逻辑,可以通过增强构造SQL查询来轻松分析,检测和解决N + 1问题。 对于GraphQL动态解析的字段,并不是那么简单。 幸运的是,Facebook正在率先解决此问题的一种可能的解决方案: DataLoader

As the name implies, DataLoader is a utility one can use to read data from databases and make it available to GraphQL resolver functions. We can use DataLoader instead of reading the data directly from databases with SQL queries, and DataLoader will act as our agent to reduce the actual SQL queries we send to the database.

顾名思义,DataLoader是一种实用程序,可以用来从数据库读取数据并将其提供给GraphQL解析器功能。 我们可以使用DataLoader来代替直接从具有SQL查询的数据库中读取数据,而DataLoader将充当我们的代理,以减少发送到数据库的实际SQL查询。

DataLoader uses a combination of batching and caching to accomplish that. If the same client request resulted in a need to ask the database about multiple things, DataLoader can be used to consolidate these questions and batch-load their answers from the database. DataLoader will also cache the answers and make them available for subsequent questions about the same resources.

DataLoader结合使用批处理和缓存来完成此任务。 如果同一客户请求导致需要向数据库询问多个问题,则可以使用DataLoader合并这些问题并从数据库中批量加载其答案。 DataLoader还将缓存答案,并使答案可用于有关相同资源的后续问题。

Thanks for reading.

谢谢阅读。

Learning React or Node? Checkout my books:

学习React还是Node? 结帐我的书:

翻译自: https://www.freecodecamp.org/news/rest-apis-are-rest-in-peace-apis-long-live-graphql-d412e559d8e4/

graph-ql

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值