React 中的 GraphQL
大家好👋🏼,今天我们将讨论 graphQL 以及它如何与 React 协同工作。我们还会介绍一个叫做 Apollo 的流行库,它可以帮助处理包括 React 在内的大多数前端框架中的 GraphQL 请求。
目录
- 什么是 GraphQL
- REST 与 GraphQL
- 向 REST 和 GraphQL API 发出请求
- 使用 Apollo 发出 GraphQL 请求
- 你应该使用 GraphQL 吗?
什么是 GraphQL
GraphQL(于 2015 年公开发布)是一种用于 API 和服务器端运行时的查询语言,用于使用现有数据(如 GraphQL 文档中所述)执行这些查询。简而言之,GraphQL 是一种与 API 交互的方式,它涉及使用查询语言发送请求,服务器根据查询发送响应。当我们想要编辑或更新特定文档时,此查询也可以采用变更的形式。GraphQL 使用模式(schema),模式只是一些规则,用于规定我们可以查询或变更的数据类型,以及可以对其进行的查询或变更。
REST 与 GraphQL
REST(表述性状态转移)是构建 API 的事实标准(有些人认为现在仍然是),因为与其前身(SOAP 和 CORBA)相比,它在使用 API 时实现了极大的简化。使用 REST:
- 每个请求都是独立处理的,因此,请求必须附带服务器成功处理所需的每一点信息。
- REST 还带来了 HTTP 动词的使用:GET、POST、PUT、PATCH、DELETE、OPTIONS 等
看起来 REST 已经做了很多好事,那么为什么,为什么我们要放弃我们好的旧 REST 而选择这个新的(REST 在 2000 年流行起来的)工具呢?
尽管我们的 RESTful API 很好,但它们也有一些缺点:
无国籍
这实际上似乎兼具两种优势,因为它也可能带来好处。我们不在服务器上处理状态,这使得我们的服务器轻量级,并降低了其复杂性,但这种状态管理被推到了前端,从而增加了其复杂性。
安全
与 REST API 相比,SOAP API 更安全,因为它们遵循更严格的安全协议,但显然需要更多的管理。
数据获取过度/不足
假设我们有一个电商应用,需要获取特定用户产品的评论。我们可能会有一个获取用户列表的路由,并且可以让这个路由返回特定用户的所有产品以及每个产品的评论。如果我们只需要用户名,就会出现数据过度获取的情况,因为我们会同时获取产品和评论。
另一方面,我们可以将其拆分成三个路由,一个路由获取所有用户,另一个路由获取某个用户拥有的商品列表,最后再一个路由获取该商品的评论。这样的话,数据获取量就会不足,因为我们必须发起 3 次请求才能得到想要的响应。
最后,我们可以设置两条getUsers
路由,一条只返回用户列表,另一条同时返回产品和评论。然而,这会破坏我们的 DRY(不要重复自己)规则,并可能增加服务器的复杂性。
GraphQL 通过使用其查询语言帮助我们轻松解决了最后一个问题,因为我们在每个请求中都精确指定了我们想要从服务器获取的内容。REST 和 GraphQL 可以在一台服务器上一起使用,但这也会增加复杂性。
向 REST 和 GraphQL API 发出请求
向这两个 API 发送请求是类似的,因为它们都使用 JSON 来发送和接收数据。
axios({
method: 'get',
url: 'https://jsonplaceholder.typicode.com/todos/1',
// data: {
// firstName: 'Finn',
// lastName: 'Williams'
// }
}).then((resp) => {
console.log(resp.data);
});
上面的代码是使用axios
包向 REST API 发送请求的典型方法。method
代表 HTTP 动词, 代表data
我们希望随请求一起发送的请求主体。
使用 GraphQL,所有请求都是 POST 请求,通常发往特定路由/graphql
,代码片段如下:
const body = {
query: `query GetProductById($id: String){
getProductById(id: $id){
name
price
imageUrl
}
}`,
variables: {
id: productId
}
}
axios({
method: 'post',
url: 'https://www.mygraphqlserver.com/graphql,
data: body
}).then((resp) => {
console.log(resp.data);
});
我们将查询(或突变)写在模板字面量中,并将变量写在一个对象中。变量只是代码中我们想要传递给查询的值。body 对象的键query
和variables
必须按照上述命名,才能确保 graphQL 请求成功。
使用 Apollo 发出 GraphQL 请求
Apollo 是一个库,可以在客户端用于与 GraphQL 服务器通信,也可以用作客户端的状态管理库,还可以用于在后端设置 GraphQL 服务器。在客户端使用 Apollo(并利用其状态管理功能)时,它会将 GraphQL 服务器模式与我们在客户端提供的模式(客户端模式代表我们的客户端状态)结合起来。发出请求时,我们会在查询中指定 Apollo 应该在客户端还是服务器上进行检查。不过,本教程中我们不会使用 Apollo 的状态管理功能。
首先,通过运行创建一个 React App,yarn create react-app apollo-app
然后通过运行安装 Apollo 和 GraphQL yarn apollo/client graphql
。
前往 index.js 文件并粘贴以下代码:
import React from "react";
import ReactDOM from "react-dom";
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client'
import App from "./App";
const cache = new InMemoryCache()
const client = new ApolloClient({
uri: 'https://mygraphqlserver.com',
cache
})
ReactDOM.render(<ApolloProvider client={client}>
<App />
</ApolloProvider>, document.getElementById("root"));
我们只需创建client
传入 GraphQL 服务器 URL 和 即可cache
。client
然后将对象作为 prop 传递给ApolloProvider
。这使我们能够使用 Apollo 在组件中发出 GraphQL 请求。
然后在要发出请求的组件中,在本例中是 App.js:
import React from "react";
import { useQuery, gql } from '@apollo/client'
import "./style.css";
const GET_COLLECTIONS = gql`
query GetProductById($id: String){
getProductById(id: $id){
name
price
imageUrl
}
}`
export default function App() {
const {loading, error, data} = useQuery(GET_COLLECTIONS,{
id: productId //Where id is the product id
})
console.log(error,data)
if(loading) return <h1>Loading...</h1>
if(error) return <h1>An Error Occurred </h1>
return (
<div>
<h1>Hello StaBlitz!</h1>
<p>Start editing to see some magic happen :)</p>
</div>
);
}
在组件中,我们首先导入useQuery
. ,gql
.useQuery
帮助我们实际发出请求, .gql
帮助我们创建查询(或突变)。将查询作为第一个参数传递给useQuery
函数。如果存在变量(就像我们一样),则将它们作为第二个参数传递给useQuery
函数。
你应该使用 GraphQL 吗?
嗯,就像软件工程中的大多数事情一样,这得看情况。GraphQL 自发布以来就越来越受欢迎,主要是因为它解决了一些问题,也可能是因为它得到了 Meta(Facebook)的支持。它已经积累了越来越多的用户,似乎已经成为 REST 的强劲对手,但大多数公司仍在使用 REST。我的建议是,在业余项目中尝试一下 GraphQL,因为学习新东西并没有什么损失😏🤷🏽♂️。
欢迎评论你对 GraphQL 取代 REST 的看法,以及你认为我在文章中遗漏的任何其他内容。
感谢阅读这篇文章❤。下次再见,我的用户名是@the_dro
_。