当创建web服务应用程序时,可以选择使用REST或GraphQL作为通信模式。两者都可能在HTTP上使用JSON,但有不同的优点和缺点。
本文主要比较GraphQL和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}"更新产品
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}"获取产品列表
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 }通过订单获取单个产品
要获取产品及其订单,通常需要先调用产品列表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的相关问题。
GraphQLGraphQL 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} }"}"
{ "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" }, ... ] }}通过订单获取单个产品
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" }, ... ] } }}GraphQL优势
GraphQL允许灵活和动态的查询:
客户端只能请求Schema已定义的字段支持别名用于请求具有自定义键值的字段客户端可以使用查询来管理返回结果的顺序客户端可以更好地与API中的任何更改解耦GraphQL倾向于避免昂贵的操作,通常可以使用GraphQL在一个请求中获取所需的所有数据。
何时使用RESTGraphQL不能替代REST。在以下情况下,可能更适合使用REST:
应用程序是资源驱动的,其中的操作与各个资源实体非常直接和完全地联系在一起需要web缓存,因为GraphQL本身并不支持需要文件上传,因为GraphQL本身并不支持结论选择使用REST或GraphQL作为通信模式,需要由业务场景决定。GraphQL灵活性也决定了其一定程度上的复杂性。
使用GraphQL也需要考虑在应用层面的缓存优化,和解决N+1问题的批量操作优化。