REST API:对象列表中的对象字段作为响应 JSON
REST API: fields of objects in a list of objects in response JSON
假设我们正在构建具有两个视图的单页应用程序:列表视图和详细信息视图。
在列表视图中,我们显示了一个对象列表,仅包含它们的名称,可能还有一些更简单的数据。
在详细视图中,我们展示了特定对象的所有可能字段。
因此问题来了:当我们获取 /api/items/
时,我们应该还是不应该 JSON-encode all 列出的对象的字段,或者只是列表视图中显示的那些?
换句话说,如果我们显示像
这样的食物列表
Name Price
Potato 1
Milk 2
我们的 API 是否需要像这样用 JSON 回应:
{
[
{
"name": "Potato",
"quantity": "1 kg",
"origin": "Egypt",
"manufacturer": "Egypt Farmers",
"price": 1,
"packaging": "String bag",
"_type": "Food"
},
{
"name": "Milk",
"quantity": "1 litre",
"origin": "Finland",
"manufacturer": "Valio",
"price": 2,
"packaging": "Tetra Pak",
"_type": "Food"
},
]
}
或者像这样:
{
[
{
"name": "Potato",
"price": 1,
"_type": "Food"
},
{
"name": "Milk",
"price": 2,
"_type": "Food"
},
]
}
RESTful API 应该集中于所代表的资源,而不一定是如何使用这些资源。
在 master/detail 场景中,通常主对象将包含主对象的详细信息,并包括其详细信息列表(包括每个详细信息的 link 到 API资源。所以 /api/items/ 可能看起来像这样:
{
items: [
{ name: 'item 1', href: '/api/items/1' },
{ name: 'item 2', href: '/api/items/2' }
]
}
详细信息资源将包含项目列表中单个项目的属性。所以 /api/items/{itemName} api 可能看起来像这样:
{
name: 'item 1',
color: 'blue',
weight: 100,
id: '/api/items/1'
}
所以这可能最接近您的第二种情况。此模型有许多优点:它可能与您的 api 正在访问的域模型相匹配,它使每个 api 非常简单且用途单一,易于扩展,甚至可以扩展到非常大列出。缺点是可能会导致客户端更加复杂。
通常的答案可能是:这完全取决于 ;)
如果连接受限或不稳定(例如 LTE 甚至 wifi 等移动连接),最好的办法是 return 填写所有字段的整个资源列表并使用两个视图上的相同数据。在我工作的公司中,我们经常采用这种方法,因为我们的后端几乎总是为移动应用程序提供数据。
第二个想法是使用一种称为字段或资源扩展的机制。通常,向端点发出请求,要 returned 的资源字段包含在该请求中:
/api/items?fields=(name, quantity, origin, whatever)
这种机制非常方便,因为您可以使用此端点为多个视图提供服务,而不会损失任何性能。
我个人会使用两个端点。一个 /api/items/
端点内置 field/resource 扩展机制(可以扩展的字段列表有限),第二个端点 /api/items/{itemID}/
到 return 具有所有的特定项目数据。这也是最RESTful的做法
假设我们正在构建具有两个视图的单页应用程序:列表视图和详细信息视图。
在列表视图中,我们显示了一个对象列表,仅包含它们的名称,可能还有一些更简单的数据。
在详细视图中,我们展示了特定对象的所有可能字段。
因此问题来了:当我们获取 /api/items/
时,我们应该还是不应该 JSON-encode all 列出的对象的字段,或者只是列表视图中显示的那些?
换句话说,如果我们显示像
这样的食物列表Name Price
Potato 1
Milk 2
我们的 API 是否需要像这样用 JSON 回应:
{
[
{
"name": "Potato",
"quantity": "1 kg",
"origin": "Egypt",
"manufacturer": "Egypt Farmers",
"price": 1,
"packaging": "String bag",
"_type": "Food"
},
{
"name": "Milk",
"quantity": "1 litre",
"origin": "Finland",
"manufacturer": "Valio",
"price": 2,
"packaging": "Tetra Pak",
"_type": "Food"
},
]
}
或者像这样:
{
[
{
"name": "Potato",
"price": 1,
"_type": "Food"
},
{
"name": "Milk",
"price": 2,
"_type": "Food"
},
]
}
RESTful API 应该集中于所代表的资源,而不一定是如何使用这些资源。
在 master/detail 场景中,通常主对象将包含主对象的详细信息,并包括其详细信息列表(包括每个详细信息的 link 到 API资源。所以 /api/items/ 可能看起来像这样:
{
items: [
{ name: 'item 1', href: '/api/items/1' },
{ name: 'item 2', href: '/api/items/2' }
]
}
详细信息资源将包含项目列表中单个项目的属性。所以 /api/items/{itemName} api 可能看起来像这样:
{
name: 'item 1',
color: 'blue',
weight: 100,
id: '/api/items/1'
}
所以这可能最接近您的第二种情况。此模型有许多优点:它可能与您的 api 正在访问的域模型相匹配,它使每个 api 非常简单且用途单一,易于扩展,甚至可以扩展到非常大列出。缺点是可能会导致客户端更加复杂。
通常的答案可能是:这完全取决于 ;)
如果连接受限或不稳定(例如 LTE 甚至 wifi 等移动连接),最好的办法是 return 填写所有字段的整个资源列表并使用两个视图上的相同数据。在我工作的公司中,我们经常采用这种方法,因为我们的后端几乎总是为移动应用程序提供数据。
第二个想法是使用一种称为字段或资源扩展的机制。通常,向端点发出请求,要 returned 的资源字段包含在该请求中:
/api/items?fields=(name, quantity, origin, whatever)
这种机制非常方便,因为您可以使用此端点为多个视图提供服务,而不会损失任何性能。
我个人会使用两个端点。一个
/api/items/
端点内置 field/resource 扩展机制(可以扩展的字段列表有限),第二个端点/api/items/{itemID}/
到 return 具有所有的特定项目数据。这也是最RESTful的做法