我的后端有以下对象结构:
包含一些字段和产品报价列表的报价。
实际上在用户界面中,用户可以打开他的报价,单击编辑按钮并修改、添加新的、删除现有的产品报价、修改报价字段。他单击“确定”(应用更改)
如何为此设计 RESTful API?
我考虑的选项:
我个人认为选项 2. 对于我的需求来说是最方便的,但我不想创建一个怪物。
大家觉得怎么样?
我发现您面临的问题之一是在设计 REST API 时,您应该注意原子性,特别是对于在单个请求中处理多个操作或资源修改的端点。确保请求中的所有更改均已成功应用,或者没有应用,从而防止部分更新可能导致数据不一致。
考虑使用 PATCH /offers/{offerId} 端点来更新商品及其关联的产品商品。如果系统在处理过程中遇到错误(无效的 ProductOffer 数据),原子性可确保不会应用部分更改。
在这种情况下:
如果强制执行原子性,则不会应用任何更新,并且客户端将收到错误响应。 如果不强制执行原子性,则部分报价可能会被更新,从而给客户端留下部分修改的报价和不一致的数据。
另外,我认为您想要遵循的方法(选项 1、2 或 3)是对您的软件进行修补。如果您以一种轻松的方式实现端点,考虑到原子性,它将为您省去很多麻烦。在某种程度上,它会创建更多对后端的调用,人们往往会说这是一个糟糕的设计,但事实并非如此。如果您包含其他休息元素(例如缓存),那么这不是问题。 在
选项 1:尝试找出 UI 上的增量或更改会产生不同类型的问题:差异图(“差异图”问题是指您需要分析和可视化之间的差异的情况)两个图,通常通过突出显示同一图结构的两个版本之间添加、删除或修改的边和节点,本质上显示它们之间发生的变化,它通常在软件开发中用于比较不同版本的代码或数据结构 )
选项 2:您没有使用 HTTP 动词 + 原子性的 Rest 语义,这可以让您真正拥有删除正确元素的能力。
选项3:当你进行补丁时,你应该瞄准该字段,就像补丁提供而不是嵌套集合
我的建议是:
我将继续这个实施。点击以下链接:
我没有包含 HATEOAS(超媒体作为应用程序状态引擎 (HATEOAS) 是 RESTful API 中的一项原则,允许客户端通过 API 响应中的超媒体链接与应用程序交互),如果您想说您有REST API,你应该实现它,根据我的经验,并不是每个人都会达到这种程度的细节,所以你可以把它留在那里,但该 API 不是 REST,因为它不符合 REST 约束 WIKI 信息
这是该链接上提供的 swagger 定义,您可以将其粘贴到 swagger 编辑器 并检查所有详细信息:
openapi: 3.0.0
info:
title: Offer and Product API
version: 1.0.2
description: RESTful API for managing Offers and associated Products.
servers:
- url: https://api.example.com/v1
description: Main API server
paths:
/offers:
get:
summary: Get a list of all offers
responses:
'200':
description: A list of offers
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Offer'
examples:
application/json:
value: [
{
"id": "1",
"name": "Summer Discount",
"description": "Special summer discount for all items",
"createdAt": "2023-08-01T12:00:00Z"
},
{
"id": "2",
"name": "Black Friday Offer",
"description": "Huge discounts for Black Friday",
"createdAt": "2023-11-24T10:00:00Z"
}
]
post:
summary: Create a new offer
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/OfferCreateRequest'
responses:
'201':
description: Offer successfully created
content:
application/json:
schema:
$ref: '#/components/schemas/Offer'
'400':
description: Invalid request format
/offers/{offerId}:
get:
summary: Get a specific offer by its ID
parameters:
- name: offerId
in: path
required: true
schema:
type: string
description: The ID of the offer to retrieve
responses:
'200':
description: A specific offer and its details
content:
application/json:
schema:
$ref: '#/components/schemas/Offer'
examples:
application/json:
value: {
"id": "2",
"name": "Black Friday Offer",
"description": "Huge discounts for Black Friday",
"createdAt": "2023-11-24T10:00:00Z"
}
'404':
description: Offer not found
put:
summary: Replace an existing offer
parameters:
- name: offerId
in: path
required: true
schema:
type: string
description: The ID of the offer to replace
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/OfferCreateRequest'
responses:
'200':
description: Offer successfully updated
'400':
description: Invalid request format
'404':
description: Offer not found
patch:
summary: Partially update an offer
parameters:
- name: offerId
in: path
required: true
schema:
type: string
description: The ID of the offer to update
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/OfferUpdateRequest'
responses:
'200':
description: Offer successfully updated
'400':
description: Invalid request format
'404':
description: Offer not found
delete:
summary: Delete an offer
parameters:
- name: offerId
in: path
required: true
schema:
type: string
description: The ID of the offer to delete
responses:
'204':
description: Offer successfully deleted
'404':
description: Offer not found
/offers/{offerId}/products:
get:
summary: Get a list of products associated with a specific offer
parameters:
- name: offerId
in: path
required: true
schema:
type: string
description: The ID of the offer for which to retrieve products
responses:
'200':
description: A list of products for the specified offer
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Product'
examples:
application/json:
value: [
{
"id": "101",
"name": "Laptop",
"price": 899.99
},
{
"id": "102",
"name": "Smartphone",
"price": 699.99
}
]
'404':
description: Offer not found
post:
summary: Add a new product to a specific offer
parameters:
- name: offerId
in: path
required: true
schema:
type: string
description: The ID of the offer to add the product to
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProductCreateRequest'
responses:
'201':
description: Product successfully added to the offer
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
'400':
description: Invalid request format
/offers/{offerId}/products/{productId}:
get:
summary: Get a specific product by its ID within an offer
parameters:
- name: offerId
in: path
required: true
schema:
type: string
description: The ID of the offer the product belongs to
- name: productId
in: path
required: true
schema:
type: string
description: The ID of the product to retrieve
responses:
'200':
description: Product details for the specified product
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
'404':
description: Product not found
put:
summary: Replace a product within an offer
parameters:
- name: offerId
in: path
required: true
schema:
type: string
description: The ID of the offer the product belongs to
- name: productId
in: path
required: true
schema:
type: string
description: The ID of the product to replace
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProductCreateRequest'
responses:
'200':
description: Product successfully updated
'400':
description: Invalid request format
'404':
description: Product not found
patch:
summary: Partially update a product within an offer
parameters:
- name: offerId
in: path
required: true
schema:
type: string
description: The ID of the offer the product belongs to
- name: productId
in: path
required: true
schema:
type: string
description: The ID of the product to update
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProductUpdateRequest'
responses:
'200':
description: Product successfully updated
'400':
description: Invalid request format
'404':
description: Product not found
delete:
summary: Delete a specific product from an offer
parameters:
- name: offerId
in: path
required: true
schema:
type: string
description: The ID of the offer the product belongs to
- name: productId
in: path
required: true
schema:
type: string
description: The ID of the product to delete
responses:
'204':
description: Product successfully deleted
'404':
description: Product not found
components:
schemas:
Offer:
type: object
properties:
id:
type: string
description: The unique identifier for the offer
name:
type: string
description: The name of the offer
description:
type: string
description: A description of the offer
createdAt:
type: string
format: date-time
description: The date and time the offer was created
required:
- id
- name
- description
- createdAt
OfferCreateRequest:
type: object
properties:
name:
type: string
description: The name of the new offer
description:
type: string
description: A description of the new offer
required:
- name
- description
OfferUpdateRequest:
type: object
properties:
name:
type: string
description: The updated name of the offer
description:
type: string
description: The updated description of the offer
required:
- name
- description
此外,如果您仍然想采用发布整个有效负载的方法,但仍然打破 REST 约束,ODATA 实现可以为您提供提示,了解如何设计批量更新创建、检查请求正文以及您将看到提交到后端的不同帖子:
您也可以从这里的示例和插图中获得想法