Alp*_*rae 79 api rest polymorphism inheritance
我有一个对象层次结构,我需要通过RESTful API公开,我不确定我的URL应该如何构建以及它们应该返回什么.我找不到任何最佳做法.
假设我有继承动物的狗和猫.我需要对狗和猫进行CRUD操作; 我也希望能够对动物进行一般操作.
我的第一个想法是做这样的事情:
GET /animals # get all animals
POST /animals # create a dog or cat
GET /animals/123 # get animal 123
Run Code Online (Sandbox Code Playgroud)
问题是/ animals集合现在"不一致",因为它可以返回并获取不具有完全相同结构的对象(狗和猫).将集合返回具有不同属性的对象,它被认为是"RESTful"吗?
另一个解决方案是为每个具体类型创建一个URL,如下所示:
GET /dogs # get all dogs
POST /dogs # create a dog
GET /dogs/123 # get dog 123
GET /cats # get all cats
POST /cats # create a cat
GET /cats/123 # get cat 123
Run Code Online (Sandbox Code Playgroud)
但现在狗和猫之间的关系就失去了.如果想要检索所有动物,必须查询狗和猫的资源.每个新的动物子类型的URL数量也会增加.
另一个建议是通过添加以下内容来扩充第二个解决方案:
GET /animals # get common attributes of all animals
Run Code Online (Sandbox Code Playgroud)
在这种情况下,返回的动物将仅包含所有动物共有的属性,丢弃特定于狗的属性和特定于猫的属性.这允许检索所有动物,尽管细节较少.每个返回的对象都可以包含指向详细的具体版本的链接.
有什么意见或建议吗?
Bri*_*lly 37
我会建议:
为同一资源设置多个URI永远不是一个好主意,因为它可能会导致混淆和意外的副作用.鉴于此,您的单个URI应基于类似的通用方案/animals.
通过/animalsURI方法已经解决了在"基础"级别处理整个狗和猫集合的下一个挑战.
使用媒体类型中的查询参数和标识属性的组合,可以轻松解决处理狗和猫等特殊类型的最终挑战.例如:
GET /animals(Accept : application/vnd.vet-services.animals+json)
{
"animals":[
{
"link":"/animals/3424",
"type":"dog",
"name":"Rex"
},
{
"link":"/animals/7829",
"type":"cat",
"name":"Mittens"
}
]
}
Run Code Online (Sandbox Code Playgroud)
GET /animals - 得到所有的狗和猫,将返回雷克斯和连指手套GET /animals?type=dog - 得到所有的狗,只会返回雷克斯GET /animals?type=cat - 得到所有的猫,只会是连指手套然后,当创建或修改动物时,呼叫者有责任指定所涉及的动物类型:
媒体类型: application/vnd.vet-services.animal+json
{
"type":"dog",
"name":"Fido"
}
Run Code Online (Sandbox Code Playgroud)
上述有效载荷可以与a POST或PUT请求一起发送.
上述方案通过REST获得与OO继承相似的基本类似特征,并且能够在不进行大型手术或对URI方案进行任何更改的情况下添加更多特化(即更多动物类型).
在最新版本的 OpenAPI 中引入的最新增强功能的支持下,可以更好地回答这个问题。
自 JSON 模式 v1.0 起,可以使用 oneOf、allOf、anyOf 等关键字组合模式并获得验证的消息有效负载。
https://spacetelescope.github.io/understanding-json-schema/reference/combining.html
但是,在 OpenAPI(以前的 Swagger)中,模式组合已通过关键字discriminator (v2.0+) 和oneOf (v3.0+)得到增强,以真正支持多态性。
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaComposition
您的继承可以使用 oneOf(用于选择一种子类型)和 allOf(用于组合该类型及其子类型之一)的组合进行建模。下面是 POST 方法的示例定义。
paths:
/animals:
post:
requestBody:
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Fish'
discriminator:
propertyName: animal_type
responses:
'201':
description: Created
components:
schemas:
Animal:
type: object
required:
- animal_type
- name
properties:
animal_type:
type: string
name:
type: string
discriminator:
property_name: animal_type
Dog:
allOf:
- $ref: "#/components/schemas/Animal"
- type: object
properties:
playsFetch:
type: string
Cat:
allOf:
- $ref: "#/components/schemas/Animal"
- type: object
properties:
likesToPurr:
type: string
Fish:
allOf:
- $ref: "#/components/schemas/Animal"
- type: object
properties:
water-type:
type: string
Run Code Online (Sandbox Code Playgroud)