本文最初发表在 https://coderesult.com/blog/graphql-in-front-end-development/
欢迎来到我们的GraphQL深度挖掘,探讨其在前端开发中的作用。随着数字世界的不断发展,我们用来与其互动的工具和技术也在不断进化。GraphQL就是近年来获得显著发展的一种工具。
GraphQL是一种API查询语言和用于执行现有数据的运行时。它是REST的一个强大替代品,当处理复杂的数据驱动应用程序时,提供了显著的优势。
在本文中,我们将探讨GraphQL是什么,为什么在前端开发中有益,以及如何在你的项目中开始实现它。无论你是一个经验丰富的开发人员,想从REST转向GraphQL,还是你是完全新手,想了解API设计,本指南旨在提供对GraphQL在前端开发中的作用的全面理解。
请随着我们深入探讨GraphQL的世界,探索其特点、优势和实现技术。通过本文的学习,你将拥有GraphQL的坚实基础,准备好增强你的前端开发技能。让我们开始吧!
什么是GraphQL?
GraphQL是一种API查询语言和用于执行现有数据的运行时。它由Facebook于2012年开发,以解决其移动应用程序中更有效的数据加载需求,并于2015年开源。
与传统的REST API返回基于命中的端点的固定数据结构不同,GraphQL API接受复杂的查询并返回精确请求的内容。这种灵活性允许客户端决定响应数据的形状和性质,减少了RESTful服务中常见的过度获取和欠获取问题。
让我们来分解一下它的名称本身:“Graph”是指图形数据结构的概念,其中实体(节点)由关系(边缘)连接。 “QL”代表查询语言,表示它是一种用于查询数据的语言。
在GraphQL查询中,你指定你需要的数据,服务器会回复精确的数据。例如,如果你正在构建一个电影评论站点,你需要一个特定电影的标题,导演和发布日期,你可以仅请求该电影的这些字段。服务器将返回一个JSON对象,其中包含你请求的数据,没有多余的数据。
这与REST形成鲜明对比,其中你通常需要访问多个端点才能收集所需的所有数据,并且每个端点可能会返回更多的数据。
为什么在前端开发中使用GraphQL?
作为前端开发人员,我们经常需要处理复杂的数据需求。我们需要从各种来源获取数据,将其组合,并以用户友好的方式呈现。这个过程可能很具有挑战性,特别是当处理RESTful API时,通常需要多次往返服务器以获取所有必要的数据。这就是GraphQL的作用所在。
以下是在前端开发中使用GraphQL的关键优势:
1.高效的数据加载:使用GraphQL,你可以在单个查询中请求多个资源,从而减少往返服务器的次数。这可以显著提高性能,特别是在延迟高的移动网络中。
2.精确的数据获取:GraphQL允许你精确指定所需的数据,消除了过度获取和欠获取问题。这意味着你不会浪费带宽获取不必要的数据,也不会为缺失的数据进行额外的请求。
3.强类型:GraphQL模式是强类型的。这意味着API的形状和与之交互的方式是预先定义的。这可以帮助及早发现错误,并使你的代码更可靠且易于使用。
4.订阅的实时更新:GraphQL通过订阅内置支持实时更新。这允许你轻松地构建需要实时数据的功能,例如聊天应用程序或实时比分更新。
5.自动生成文档:由于GraphQL中的模式是类型化的,并且查询是可预测的,因此它可以自动生成文档。这可以使开发人员更容易理解哪些数据可用,如何获取它以及可以期望的响应数据类型。
6.进化的API:使用GraphQL,你可以向API添加新字段和类型,而不会影响现有的查询。这使得你的API可以随着时间的推移而发展,而不会破坏前端代码。
GraphQL查询、突变和订阅
在GraphQL中,有三种主要的操作类型:查询,突变和订阅。让我们深入了解每种操作类型。
查询
GraphQL中的查询相当于REST中的GET请求。它们用于从服务器获取数据。GraphQL查询的美妙之处在于它们的精度和灵活性。你可以精确地请求所需的内容,包括对象的各个字段。
以下是GraphQL查询的示例:
query {
movie(id: "1") {
title
director
releaseDate
}
}
在此查询中,我们请求具有“1”ID的电影,我们需要该电影的标题、导演和发布日期。服务器将返回一个JSON对象,其中包含精确的数据。
突变
突变是你在GraphQL中更改数据的方式。它们相当于REST中的POST、PUT和DELETE请求。与查询一样,你可以指定突变的返回数据,使你可以在突变后轻松更新客户端数据。
以下是GraphQL突变的示例:
mutation {
addMovie(title: "New Movie", director: "John Doe", releaseDate: "2023-05-18") {
id
title
}
}
在此突变中,我们正在添加一个新电影,并要求返回新创建的电影的ID和标题。
订阅
订阅是GraphQL的一项功能,允许服务器在特定事件发生时向其客户端发送数据。订阅通常使用WebSockets实现。这意味着你可以与服务器保持稳定的连接,并在数据发生更改时获取实时更新。
以下是GraphQL订阅的示例:
subscription {
movieAdded {
id
title
}
}
在此订阅中,我们请求服务器在添加新电影时通知我们。我们将接收新添加的电影的ID和标题。# 在前端上设置GraphQL
现在我们已经介绍了GraphQL的基础知识,让我们讨论如何在前端上设置它。为此,我们需要一个GraphQL客户端。GraphQL客户端的作用是帮助你处理应用程序中的GraphQL查询、变异和订阅。它还提供有用的功能,如缓存、乐观UI、错误处理等等。
有几个GraphQL客户端可用,但最受欢迎的是Apollo Client和Relay。
Apollo Client
Apollo Client是一个JavaScript的综合状态管理库,它使你能够使用GraphQL管理本地和远程数据。它与任何构建设置、任何GraphQL模式和任何GraphQL服务器兼容。
以下是Apollo Client的基本设置:
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
// Initialize Apollo Client
const client = new ApolloClient({
uri: 'https://your-graphql-endpoint.com/graphql',
cache: new InMemoryCache()
});
// Now you can run GraphQL queries
client.query({
query: gql`
query GetMovie {
movie(id: "1") {
title
director
releaseDate
}
}
`
}).then(result => console.log(result));
Relay
Relay是一个由GraphQL驱动的用于构建数据驱动React应用程序的JavaScript框架。它比Apollo Client更具有见解,并且有一个更陡峭的学习曲线,但它为复杂的高性能应用程序提供了许多好处。
以下是Relay的基本设置:
import {
Environment,
Network,
RecordSource,
Store,
} from 'relay-runtime';
// Define a function that fetches the results of an operation (query/mutation/etc)
// and returns its results as a Promise:
function fetchQuery(
operation,
variables,
) {
return fetch('/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then(response => {
return response.json();
});
}
// Create a network layer from the fetch function
const network = Network.create(fetchQuery);
const environment = new Environment({
network,
store: new Store(new RecordSource()),
});
// Now you can run GraphQL queries with Relay
将GraphQL与前端框架集成
GraphQL可以与任何可以进行HTTP请求的前端框架或库集成。然而,为了充分利用GraphQL,最好使用专用的GraphQL客户端,如Apollo Client或Relay。这些客户端提供了高级功能,如缓存、乐观UI、分页等。让我们看看如何将GraphQL与一些流行的前端框架集成。
React
React是构建用户界面的流行选择,并且与GraphQL配对很好。Apollo Client和Relay都对React提供了出色的支持。
以下是如何在React中使用Apollo Client的基本示例:
import React from 'react';
import { ApolloProvider, useQuery, gql } from '@apollo/client';
const GET_MOVIE = gql`
query GetMovie {
movie(id: "1") {
title
director
releaseDate
}
}
`;
function Movie() {
const { loading, error, data } = useQuery(GET_MOVIE);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return (
<div>
<h2>{data.movie.title}</h2>
<p>{data.movie.director}</p>
<p>{data.movie.releaseDate}</p>
</div>
);
}
function App() {
return (
<ApolloProvider client={client}>
<Movie />
</ApolloProvider>
);
}
export default App;
Angular
Apollo Client也通过apollo-angular
包支持Angular。以下是一个基本示例:
import { Component } from '@angular/core';
import { Apollo, gql } from 'apollo-angular';
const GET_MOVIE = gql`
query GetMovie {
movie(id: "1") {
title
director
releaseDate
}
}
`;
@Component({
selector: 'app-root',
template: `
<div *ngIf="loading">
Loading...
</div>
<div *ngIf="error">
Error :(
</div>
<div *ngIf="movie">
<h2>{{movie.title}}</h2>
<p>{{movie.director}}</p>
<p>{{movie.releaseDate}}</p>
</div>
`,
})
export class AppComponent {
movie: any;
loading = true;
error: any;
constructor(private apollo: Apollo) {
this.apollo
.watchQuery({
query: GET_MOVIE,
})
.valueChanges.subscribe(result => {
this.loading = result.loading;
this.movie = result.data && result.data.movie;
this.error = result.error;
});
}
}
Vue.js
对于Vue.js,你可以使用vue-apollo
插件。以下是一个基本示例:
<template>
<div>
<div v-if="$apollo.loading">
Loading...
</div>
<div v-if="error">
Error :(
</div>
<div v-if="movie">
<h2>{{movie.title}}</h2>
<p>{{movie.director}}</p>
<p>{{movie.releaseDate}}</p>
</div>
</div>
</template>
<script>
import gql from 'graphql-tag';
export default {
data() {
return {
movie: null,
error: null,
};
},
apollo: {
$loadingKey: 'loading',
movie: {
query: gql`
query GetMovie {
movie(id: "1") {
title
director
releaseDate
}
}
`,
error(error) {
this.error = error;
},
},
},
};
</script>
这些示例展示了如何在React、Angular和Vue.js中使用GraphQL获取数据。但是,Apollo Client和Relay提供了许多其他功能,可以帮助你构建复杂的数据驱动应用程序。
GraphQL中的错误处理
错误处理是任何应用程序的重要方面,GraphQL也不例外。与REST不同,你可以使用HTTP状态码来指示错误的性质,GraphQL始终从HTTP的角度返回200 OK状态代码,即使发生错误。这是因为技术上请求是成功的,即使请求的数据中存在错误。
GraphQL中的错误包含在响应的errors
字段中。errors
数组中的每个错误对象都有一个message
字段,它是一个描述性字符串,说明出了什么问题。它还可能具有locations
和path
字段,这些字段可以帮助你确定查询中出现错误的位置。
以下是一个具有错误的GraphQL响应示例:
{
"data": {
"movie": null
},
"errors": [
{
"message": "Could not find a movie with id '1'",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"movie"
]
}
]
}
使用像Apollo Client或Relay这样的GraphQL客户端时,来自服务器的错误会作为异常抛出。你可以捕获这些异常并适当地处理它们。
以下是在React组件中使用Apollo Client进行错误处理的示例:
import React from 'react';
import { useQuery, gql } from '@apollo/client';
const GET_MOVIE = gql`
query GetMovie {
movie(id: "1") {
title
director
releaseDate
}
}
`;
function Movie() {
const { loading, error, data } = useQuery(GET_MOVIE);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h2>{data.movie.title}</h2>
<p>{data.movie.director}</p>
<p>{data.movie.releaseDate}</p>
</div>
);
}
export default Movie;
在这个示例中,如果查询中有错误,我们会向用户显示错误消息。
在前端上测试GraphQL
测试是开发过程的重要部分,确保你的应用程序表现符合预期并有助于防止错误。当涉及到在前端上测试GraphQL时,你可能想要测试一些不同的方面,包括单个查询和变异、使用这些操作的组件以及客户端和服务器之间的集成。
测试查询和变异
你可能想要测试的第一件事是你的单个查询和变异。这涉及向你的GraphQL服务器发出请求并检查响应是否符合预期。
对于JavaScript应用程序,你可以使用像jest
这样的库。如果你使用Apollo Client,你可以利用@apollo/client/testing
实用程序来创建模拟客户端并针对它执行查询和变异。
以下是如何测试查询的示例:
import { MockedProvider } from '@apollo/client/testing';
import { renderHook } from '@testing-library/react-hooks';
import { useMovieQuery, GET_MOVIE } from './useMovieQuery';
const movieMock = {
request: {
query: GET_MOVIE,
variables: { id: '1' },
},
result: {
data: {
movie: {
id: '1',
title: 'Test Movie',
director: 'Test Director',
releaseDate: '2023-05-18',
},
},
},
};
it('should fetch movie', async () => {
const { result, waitForNextUpdate } = renderHook(() => useMovieQuery('1'), {
wrapper: ({ children }) => (
<MockedProvider mocks={[movieMock]} addTypename={false}>
{children}
</MockedProvider>
),
});
expect(result.current.loading).toBe(true);
await waitForNextUpdate();
expect(result.current.loading).toBe(false);
expect(result.current.data).toEqual(movieMock.result.data);
});
测试组件
除了测试你的查询和变异之外,你还需要测试使用这些操作的组件。这涉及渲染你的组件并对渲染内容进行断言。
如果你使用React,你可以使用@testing-library/react
库。如果你使用Apollo Client,你可以使用MockedProvider
组件来提供模拟客户端。
以下是如何测试组件的示例:
import React from 'react';
import { render, waitFor } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import Movie, { GET_MOVIE } from './Movie';
const movieMock = {
request: {
query: GET_MOVIE,
variables: { id: '1' },
},
result: {
data: {
movie: {
id: '1',
title: 'Test Movie',
director: 'Test Director',
releaseDate: '2023-05-18',
},
},
},
};
it('should render movie', async () => {
const { getByText } = render(
<MockedProvider mocks={[movieMock]} addTypename={false}>
<Movie id="1" />
</MockedProvider>
);
expect(getByText('Loading...')).toBeInTheDocument();
await waitFor(() => getByText('Test Movie'));
expect(getByText('Test Movie')).toBeInTheDocument();
expect(getByText('Test Director')).toBeInTheDocument();
expect(getByText('2023-05-18')).toBeInTheDocument();
});
GraphQL的性能考虑因素
虽然GraphQL提供了许多好处,但考虑性能以确保应用程序保持快速和响应很重要。当在前端上使用GraphQL时,以下是一些关键的性能考虑因素:
过度获取和欠获取
GraphQL的主要优点之一是它解决了REST API常见的过度获取和欠获取问题。使用GraphQL,你可以精确指定你需要的数据,这可以导致更有效的数据加载。但是,如果不小心,仍然可能会过度获取GraphQL。始终确保只请求你需要的数据。
缓存
缓存是通过存储昂贵操作的结果并重复使用它们来提高性能的强大技术。Apollo Client带有一个先进的缓存机制。它规范化你的数据,缓存请求并在数据更改时自动更新你的UI。确保利用此功能以避免不必要的网络请求。
批处理和去重
Apollo Client还支持查询批处理和去重。批处理允许你将多个查询组合成一个请求,减少了进行多个HTTP请求的开销。去重确保不会不必要地向服务器发送相同的查询多次。
分页
当处理大量数据列表时,一次获取所有数据通常是不切实际和低效的。相反,你可以获取有限量的数据,然后根据需要获取更多数据。GraphQL支持各种形式的分页,包括基于偏移量的分页和基于游标的分页。预取数据
预取数据是一种技术,你可以预测用户未来可能需要的数据,并在他们请求数据之前加载它。例如,当用户悬停在链接或按钮上时,你可以预取数据。这可以使你的应用程序感觉更快、更响应。
持久化查询
持久化查询是一种技术,你可以从客户端向服务器发送一个唯一标识符,而不是完整的查询。这可以减少网络负载大小并防止某些类型的攻击。Apollo Server和Apollo Client都支持持久化查询。
监控和优化性能
最后,监控GraphQL客户端的性能并识别和修复任何瓶颈是非常重要的。像Apollo Studio这样的工具可以提供有关你的GraphQL性能的见解,包括每个解析器函数的跟踪数据。
结论
在这篇探讨GraphQL在前端开发中的文章中,我们涵盖了很多内容。从了解GraphQL的基础知识,到在前端上设置它,将其与流行的框架集成,处理错误,测试和优化性能,我们看到了GraphQL如何成为构建高效、灵活和强大应用程序的有力工具。
精确定义你需要的数据的能力,结合强类型和内置实时功能,使GraphQL成为传统REST API的有力替代方案。无论你是在构建小型个人项目还是大规模生产应用程序,GraphQL都有很多优点。
然而,像任何技术一样,GraphQL并不是万能的。在决定是否使用GraphQL时,考虑你的具体用例和要求非常重要。记住,熟悉GraphQL的最好方法是使用它构建东西。那么,为什么不开始一个新项目,尝试一下GraphQL呢?
译自:https://umuralpay.com/graphql-in-front-end-development-5c78e66db798
评论(0)