深入理解RESTful与GraphQL:从数据获取到灵活查询
1. 消费RESTful Web服务
在开发中,消费RESTful Web服务是常见的数据获取方式。为了从Web服务获取初始产品和供应商数据,并确保任何更改都能触发对Web服务的更新,我们需要对初始数据进行处理。以下是移除
src/store
文件夹中
initialData.js
文件里静态数据的代码:
import { PRODUCTS, SUPPLIERS } from "./dataTypes";
export const initialData = {
modelData: {
[PRODUCTS]: [],
[SUPPLIERS]: []
},
stateData: {
editing: false,
selectedId: -1,
selectedType: PRODUCTS
}
}
通过上述代码,我们将初始的产品和供应商数据设置为空数组,后续数据将从Web服务获取。
2. 理解GraphQL
GraphQL是一种用于创建和消费API的端到端系统,它为传统的RESTful Web服务提供了更灵活的替代方案。下面是关于GraphQL的一些关键信息:
| 问题 | 答案 |
| ---- | ---- |
| 是什么? | GraphQL是一种生成API的查询语言。 |
| 为什么有用? | 它为客户端提供了灵活的数据访问方式,确保客户端仅接收所需的数据,并允许在不进行服务器端更改的情况下制定新的查询。 |
| 如何使用? | 在服务器端,使用解析器函数定义并实现模式;客户端使用GraphQL语言发送查询和请求更改。 |
| 有哪些陷阱或限制? | GraphQL复杂,编写有用的模式需要一定的技能。 |
| 有哪些替代方案? | 客户端可以使用RESTful Web服务。 |
3. 准备工作
在开始使用GraphQL之前,我们需要进行一些准备工作。首先,打开命令提示符,导航到
productapp
文件夹,并运行以下命令添加所需的包:
npm install --save-dev graphql@14.0.2
npm install --save-dev express@4.16.4
npm install --save-dev express-graphql@0.7.1
npm install --save-dev graphql-import@0.7.1
npm install --save-dev cors@2.8.5
这些包的作用如下:
| 名称 | 描述 |
| ---- | ---- |
| graphql | 包含GraphQL的参考实现。 |
| express | 提供可扩展的HTTP服务器,是本章使用的GraphQL服务器的基础。 |
| express-graphql | 通过
express
包提供基于HTTP的GraphQL服务。 |
| graphql-import | 允许在多个文件中定义GraphQL模式,并比直接读取文件更轻松地导入模式。 |
| cors | 为Express HTTP服务器启用跨域资源共享(CORS)。 |
安装完包后,在
productapp
文件夹中运行以下命令启动开发工具:
npm start
启动完成后,会打开一个新的浏览器窗口并显示
http://localhost:3000
。
4. 创建GraphQL服务器
创建GraphQL服务器的过程包括创建模式、编写解析器和启动服务器。以下是详细步骤:
-
创建模式
:在
src/graphql
文件夹中创建一个名为
schema.graphql
的文件,内容如下:
type product {
id: ID!,
name: String!,
category: String!
price: Float!
}
type supplier {
id: ID!,
name: String!,
city: String!,
products: [ID]
}
type Query {
products: [product],
suppliers: [supplier]
}
这个模式定义了两个自定义类型:
product
和
supplier
,并定义了两个查询:
products
和
suppliers
。
-
创建解析器
:在
src/graphql
文件夹中创建一个名为
resolvers.js
的文件,代码如下:
var data = require("../../restData")();
module.exports = {
products: () => data.products,
suppliers: () => data.suppliers
}
每个解析器是一个函数,其名称对应于模式中定义的查询,并返回符合模式声明格式的数据。
-
创建服务器
:在
productapp
文件夹中创建一个名为
graphqlServer.js
的文件,代码如下:
var { buildSchema } = require("graphql");
var { importSchema } = require("graphql-import");
var express = require("express");
var graphqlHTTP = require("express-graphql")
var cors = require("cors")
var schema = importSchema("./src/graphql/schema.graphql");
var resolvers = require("./src/graphql/resolvers");
var app = express();
app.use(cors());
app.use("/graphql", graphqlHTTP({
schema: buildSchema(schema),
rootValue: resolvers,
graphiql: true,
}));
app.listen(3600, () => console.log("GraphQL Server Running on Port 3600"));
启动GraphQL服务器,打开新的命令提示符,导航到
productapp
文件夹,运行以下命令:
node graphqlServer.js
启动后,打开浏览器并导航到
http://localhost:3600/graphql
,可以看到GraphiQL工具。
5. 执行GraphQL查询
使用GraphiQL工具可以轻松执行查询。例如,要查询所有供应商对象,在GraphiQL窗口的左窗格中输入以下查询:
query {
suppliers {
id,
name,
city,
products
}
}
点击“Execute Query”按钮发送请求,服务器将返回以下结果:
{
"data": {
"suppliers": [
{
"id": "1",
"name": "Surf Dudes",
"city": "San Jose",
"products": ["1","2"]
},
{
"id": "2",
"name": "Goal Oriented",
"city": "Seattle",
"products": ["3","4","5"]
},
{
"id": "3",
"name": "Bored Games",
"city": "New York",
"products": ["6","7","8","9"]
}
]
}
}
通过这个基本查询,客户端能够选择所需的字段并指定其显示顺序。
6. 查询相关数据
GraphQL的一个强大特性是它能轻松支持查询中的相关数据,允许单个查询返回包含多种类型的结果。我们对
schema.graphql
文件中的
supplier
数据类型的
products
字段进行修改:
type product {
id: ID!,
name: String!,
category: String!
price: Float!
}
type supplier {
id: ID!,
name: String!,
city: String!,
products: [product]
}
type Query {
products: [product],
suppliers: [supplier]
}
为了支持这个更改,我们需要处理解析器中使用的数据,修改
resolvers.js
文件如下:
var data = require("../../restData")();
module.exports = {
products: () => data.products,
suppliers: () => data.suppliers.map(s => ({
...s, products: () => s.products.map(id =>
data.products.find(p => p.id === Number(id)))
}))
}
停止GraphQL服务器(使用
Control+C
),然后重新启动:
node graphqlServer.js
导航到
http://localhost:3600/graphql
,在GraphiQL窗口的左窗格中输入以下查询:
query {
suppliers {
id,
name,
city,
products {
name
}
}
}
通过上述查询,我们可以在单个查询中获取供应商及其相关产品的数据。
7. 获取GraphQL服务的模式详细信息
如果无法编写自己的模式,可以通过以下方法获取GraphQL服务的模式详细信息:
-
查看开发者文档
:许多公共GraphQL服务会发布全面的模式文档,如GitHub API(https://developer.github.com/v4 )。
-
使用GraphiQL或类似工具
:大多数工具支持模式导航,例如GraphiQL可以通过其“Docs”链接轻松探索模式。
-
使用GraphQL内省功能
:如果没有文档且不支持GraphiQL,可以使用内省功能发送关于模式的查询,例如:
{
__schema {
queryType {
fields {
name
}
}
}
}
综上所述,GraphQL为我们提供了一种更灵活的数据查询和获取方式,通过合理使用模式、解析器和查询,我们可以高效地满足不同的业务需求。但在使用时,也需要注意其复杂性和可能带来的成本问题。
深入理解RESTful与GraphQL:从数据获取到灵活查询
8. GraphQL查询过滤
在GraphQL中,我们可以通过指定查询参数来过滤结果。以下是一个示例,展示如何在查询中添加过滤条件。假设我们要查询价格大于某个值的产品,我们可以修改
schema.graphql
文件,添加一个带参数的查询:
type product {
id: ID!,
name: String!,
category: String!
price: Float!
}
type Query {
products(priceGreaterThan: Float): [product]
}
然后修改
resolvers.js
文件来处理这个参数:
var data = require("../../restData")();
module.exports = {
products: (args) => {
if (args.priceGreaterThan) {
return data.products.filter(p => p.price > args.priceGreaterThan);
}
return data.products;
}
}
在GraphiQL中,我们可以这样使用这个带参数的查询:
query {
products(priceGreaterThan: 50) {
id
name
price
}
}
这样就可以只获取价格大于50的产品数据。
9. 使用GraphQL进行数据修改
GraphQL不仅可以用于查询数据,还可以用于修改数据。我们可以在
schema.graphql
中定义突变(mutations)来实现数据的修改。以下是一个简单的示例,定义一个用于更新产品价格的突变:
type product {
id: ID!,
name: String!,
category: String!
price: Float!
}
type Mutation {
updateProductPrice(id: ID!, newPrice: Float!): product
}
type Query {
products: [product],
suppliers: [supplier]
}
然后在
resolvers.js
中实现这个突变:
var data = require("../../restData")();
module.exports = {
products: () => data.products,
suppliers: () => data.suppliers,
updateProductPrice: (args) => {
const product = data.products.find(p => p.id === args.id);
if (product) {
product.price = args.newPrice;
return product;
}
return null;
}
}
在GraphiQL中,我们可以这样使用这个突变:
mutation {
updateProductPrice(id: "1", newPrice: 60) {
id
name
price
}
}
执行这个突变后,ID为1的产品价格将被更新为60。
10. 参数化查询
为了提高查询的灵活性,我们可以使用查询变量。以下是一个使用查询变量的示例:
query GetProducts($priceGreaterThan: Float) {
products(priceGreaterThan: $priceGreaterThan) {
id
name
price
}
}
在GraphiQL的变量输入框中,我们可以这样设置变量:
{
"priceGreaterThan": 50
}
这样就可以动态地改变查询的过滤条件。
11. 使用查询片段
当我们需要在多个查询中请求相同的字段集时,可以使用查询片段。以下是一个示例:
fragment ProductInfo on product {
id
name
price
}
query {
products {
...ProductInfo
}
suppliers {
id
name
products {
...ProductInfo
}
}
}
通过使用查询片段,我们可以避免重复编写相同的字段,提高代码的可维护性。
12. GraphQL与RESTful的对比总结
| 对比项 | RESTful | GraphQL |
|---|---|---|
| 数据获取灵活性 | 客户端可能需要多次请求并合并数据,获取的数据可能包含不需要的字段 | 客户端可以精确控制请求的数据字段,一次请求获取所需的所有数据 |
| 开发难度 | 易于上手,但随着客户端需求变化可能变得不灵活 | 相对复杂,编写有用的模式需要一定技能,但能更好地适应客户端需求变化 |
| 服务器压力 | 客户端可能会请求大量不必要的数据,增加服务器压力 | 客户端只请求所需的数据,减少服务器压力 |
13. 选择合适的技术
在选择使用RESTful还是GraphQL时,需要考虑以下因素:
-
项目规模和复杂度
:对于小型项目或需求相对固定的项目,RESTful可能是一个简单直接的选择;对于大型项目或需求变化频繁的项目,GraphQL可能更合适。
-
开发团队技能
:如果团队成员对RESTful比较熟悉,且项目需求不需要高度的灵活性,那么可以继续使用RESTful;如果团队有能力学习和掌握GraphQL,且项目需要更好地适应变化,那么可以考虑使用GraphQL。
graph LR
A[选择技术] --> B{项目规模和复杂度}
A --> C{开发团队技能}
B --> D[小型/需求固定: RESTful]
B --> E[大型/需求多变: GraphQL]
C --> F[熟悉RESTful且需求简单: RESTful]
C --> G[有能力掌握GraphQL且需求多变: GraphQL]
总之,GraphQL和RESTful各有优缺点,我们需要根据项目的具体情况来选择合适的技术,以实现高效的数据处理和业务需求的满足。在实际开发中,可以结合两者的优势,构建出更强大的应用程序。
超级会员免费看
17

被折叠的 条评论
为什么被折叠?



