选择使用REST或GraphQL作为通信模式,需要由业务场景决定。GraphQL灵活性也决定了其一定程度上的复杂性。使用GraphQL也需要考虑在应用层面的缓存优化,和解决N+1问题的批量操作优化。
概述 当创建web服务应用程序时,可以选择使用REST或GraphQL作为通信模式。两者都可能在HTTP上使用JSON,但有不同的优点和缺点。
本文主要比较GraphQL和REST,以操作一个产品数据库示例,比较两种解决方案在执行相同的客户端操作时的差异:
创建处于草稿状态的产品 更新产品详细信息 获取产品列表 获取单个产品及其订单的详细信息 REST REST(Representational State Transfer,代表性状态传输)的主要数据元素称为Resource。在本例中,资源是“产品”。
复制 curl --request POST 'http://localhost:8081/product' \
--header 'Content-Type: application/json' \
--data '{
"name" : "Watch" ,
"description" : "Special Swiss Watch" ,
"status" : "Draft" ,
"currency" : "USD" ,
"price" : null ,
"imageUrls" : null ,
"videoUrls" : null ,
"stock" : null ,
"averageRating" : null
} '
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 复制 curl --request PUT 'http://localhost:8081/product/{product-id}' \
--header 'Content-Type: application/json' \
--data '{
"name" : "Watch" ,
"description" : "Special Swiss Watch" ,
"status" : "Draft" ,
"currency" : "USD" ,
"price" : 1200.0 ,
"imageUrls" : [
"https://graphqlvsrest.com/imageurl/product-id"
] ,
"videoUrls" : [
"https://graphqlvsrest.com/videourl/product-id"
] ,
"stock" : 10 ,
"averageRating" : 0.0
} '
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 复制 curl --request GET 'http://localhost:8081/product?size=10&page=0'
复制 {
"id" : 1 ,
"name" : "T-Shirt" ,
"description" : "Special beach T-Shirt" ,
"status" : Published,
"currency" : "USD" ,
"price" : 30.0 ,
"imageUrls" : [ "https://graphqlvsrest.com/imageurl/1" ] ,
"videoUrls" : [ "https://graphqlvsrest.com/videourl/1" ] ,
"stock" : 10 ,
"averageRating" : 3.5
}
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 要获取产品及其订单,通常需要先调用产品列表API,然后调用订单资源以查找相关订单:
复制 curl --request GET 'localhost:8081/order?product-id=1'
复制 {
"id" : 1 ,
"productId" : 1 ,
"customerId" : "de68a771-2fcc-4e6b-a05d-e30a8dd0d756" ,
"status" : "Delivered" ,
"address" : "43-F 12th Street" ,
"creationDate" : "Mon Jan 17 01:00:18 GST 2022"
}
除了获取所有产品的原始操作外,还需要对每个感兴趣的产品执行一次此操作,这会产生N+1的相关问题。
GraphQL GraphQL API操作包含Queries和Mutations。Queries负责获取数据,Mutations用于创建和更新。
Queries和Mutations的Schema模式定义了客户端可能的请求和响应。
复制 curl --request POST 'http://localhost:8081/graphql' \
--header 'Content-Type: application/json' \
--data \
'{
"query": "mutation {saveProduct (
product: {
name: \"Bed-Side Lamp\",
price: 24.0,
status: \"Draft\",
currency: \"USD\"
}){ id name currency price status}
}"
}'
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 复制 {
"data" : {
"saveProduct" : {
"id" : "12" ,
"name" : "Bed-Side Lamp" ,
"currency" : "USD" ,
"price" : 24.0 ,
"status" : "Draft"
}
}
}
复制 curl --request POST 'http://localhost:8081/graphql' \
--header 'Content-Type: application/json' \
--data \
'{"query": "mutation {updateProduct(
id: 11
product: {
price: 14.0,
status: \"Publish\"
}){ id name currency price status }
}","variables":{}}'
复制 {
"data" : {
"updateProduct" : {
"id" : "12" ,
"name" : "Bed-Side Lamp" ,
"currency" : "USD" ,
"price" : 14.0 ,
"status" : "Published"
}
}
}
复制 curl --request POST 'http://localhost:8081/graphql' \
--header 'Content-Type: application/json' \
--data \
'{
"query": "query {products(size:10,page:0){id name status}}"
}'
复制 {
"data" : {
"products" : [
{
"id" : "1" ,
"name" : "T-Shirt" ,
"status" : "Published"
} ,
...
]
}
}
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 复制 curl --request POST 'http://localhost:8081/graphql' \
--header 'Content-Type: application/json' \
--data \
'{
"query": "query {product(id:1){ id name orders{customerId address status creationDate}}}"
}'
复制 {
"data" : {
"product" : {
"id" : "1" ,
"name" : "T-Shirt" ,
"orders" : [
{
"customerId" : "de68a771-2fcc-4e6b-a05d-e30a8dd0d756" ,
"status" : "Delivered" ,
"address" : "43-F 12th Street" ,
"creationDate" : "Mon Jan 17 01:00:18 GST 2022"
} ,
...
]
}
}
}
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. GraphQL优势 GraphQL允许灵活和动态的查询:
客户端只能请求Schema已定义的字段 支持别名用于请求具有自定义键值的字段 客户端可以使用查询来管理返回结果的顺序 客户端可以更好地与API中的任何更改解耦 GraphQL倾向于避免昂贵的操作,通常可以使用GraphQL在一个请求中获取所需的所有数据。
何时使用REST GraphQL不能替代REST。在以下情况下,可能更适合使用REST:
应用程序是资源驱动的,其中的操作与各个资源实体非常直接和完全地联系在一起 需要web缓存,因为GraphQL本身并不支持 需要文件上传,因为GraphQL本身并不支持 结论 选择使用REST或GraphQL作为通信模式,需要由业务场景决定。GraphQL灵活性也决定了其一定程度上的复杂性。
使用GraphQL也需要考虑在应用层面的缓存优化,和解决N+1问题的批量操作优化。