我需要使用json格式通过api调用将python后端中的数据传递到前端。在python后端,数据是字典结构,我可以轻松地直接转换为json。但我应该吗?
我的前端开发人员认为答案是否定的,原因与最佳做法有关。
但我挑战:
最好是在python中构造一个json,还是应该转换为其他形式,例如几个数组(在下面的示例中需要)?
或者,换句话说:
与通过jsons接口信息的集合/ dicts / maps /数组相关的管理原则应该是什么?
我已经做了一些谷歌搜索,但我没有遇到太多直接解决这个问题。链接将不胜感激。
(请注意以下示例:当然,如果将数据写入数据库,最好直接访问数据库,但我们假设情况并非如此)
示例:
在后端有一组名为pets
的对象:
集合中的每个项目都有一个唯一的pet_id
,一些非可选属性,例如name
和date_of_birth
,一些可选属性registration_certificate_nr
,adopted_from_kennel
,一些列表如siblings
和children
以及一些对象,如medication
假设前端在某个时刻需要所有这些信息,它可能是
{
"pets": {
"17-01-24-01": {
"name": "Buster",
"date_of_birth": "04/01/2017",
"registration_certificate_nr": "AAD-1123-1432"
},
"17-03-04-01": {
"name": "Hooch",
"date_of_birth": "05/02/2015",
"adopted_from_kennel": "Pretoria Shire",
"children": [
"17-05-01-01",
"17-05-01-02",
"17-05-01-03"
]
},
"17-05-01-01": {
"name": "Snappy",
"date_of_birth": "17-05-01",
"siblings": [
"17-05-01-02",
"17-05-01-03"
]
},
"17-05-01-02": {
"name": "Gizmo",
"date_of_birth": "17-05-01",
"siblings": [
"17-05-01-01",
"17-05-01-03"
]
},
"17-05-01-03": {
"name": "Toothless",
"date_of_birth": "17-05-01",
"siblings": [
"17-05-01-01",
"17-05-01-03"
],
"medication": [
{
"name": "anti-worm",
"code": "aw445",
"dosage": "1 pill per day"
},
{
"name": "disinfectant",
"code": "pdi-2",
"dosage": "as required"
}
]
}
}
}
答案 0 :(得分:2)
JSON格式化是一个有点主观的问题,相关的分歧通常最好在同事之间解决。
话虽如此,在问题中对JSON格式有一些潜在的有效批评,特别是如果我们试图创建一致的RESTful API。
突出的2个痛点:
地图集合以JSON表示,它不符合JSON标准,或者特别是RESTful。
所有宠物对象都没有定义id
。问题中提到pet_id
,但它似乎与宠物对象本身分开维护。如果在问题的pets
地图中访问了某个值,那么API的用户必须手动将pet_id
添加到提供的宠物对象中,以便在该行下方提供该ID,当完整的JSON可能不再可用时。
在这种情况下,我们最接近指导标准的是REST architectural style和JSON standard。
我们可以从查看JSON标准开始。以下是JSON wiki:
的引用JavaScript语法定义了JSON标准中未包含的几种本机数据类型:Map,Set,Date,Error,Regular Expression,Function,Promise和
undefined
。
这里的关键点是JSON并不代表地图数据类型。 Python字典是一个地图实现,因此直接将字典序列化为JSON以表示类似地图的集合与JSON的预期用法相违背。
对于像pet这样的单个对象,JSON对象是合适的,但对于集合,有一个选项:JSON数组。在这个答案中有一个使用JSON数组的用法示例。
可能存在偏离标准的边缘情况有意义,但在这种情况下我没有看到原因。
从RESTful设计角度来看,JSON格式也存在一些缺点。 RESTful API设计很不错,因为它鼓励人们保持简单和一致。它也恰好是事实上的行业标准。
在RESTful HTTP API中,这是获取单个宠物资源的方式:
Request: GET /api/pets/17-01-24-01
Response: 200 {
"id": "17-01-24-01",
"name": "Buster",
"date_of_birth": "04/01/2017",
"registration_certificate_nr": "AAD-1123-1432"
}
响应是一个完全定义的资源,具有明确定义的id
。它也是宠物最简单的完整JSON表示。
接下来,我们定义了获取多个宠物资源的样子,假设只定义了2只宠物:
Request: GET /api/pets
Response: 200 [
{
"id": "17-01-24-01",
"name": "Buster",
"date_of_birth": "04/01/2017",
"registration_certificate_nr": "AAD-1123-1432"
},
{
"id": "17-03-04-01",
"name": "Hooch",
"date_of_birth": "05/02/2015",
"adopted_from_kennel": "Pretoria Shire",
"children": [
"17-05-01-01",
"17-05-01-02",
"17-05-01-03"
]
}
]
上述响应格式是使单一资源响应格式多元化的最直接方式,从而使API尽可能简单和一致。 (为简洁起见,我只使用了问题中的2个样本资源)。同样,id
被明确定义,并且属于它们各自的宠物对象。
将地图密钥添加到上述格式无效。
问题中JSON格式的支持者可能建议只将id
字段添加到每个宠物对象中以解决痛点2,但这会引起在响应中重复数据的问题。为什么id
需要在对象的内部和外部?当然它应该只在内部?消除冗余数据后,结果将类似于上面的响应。
这是REST参数。在某些情况下,REST并没有真正发挥作用,但这远非如此。
PS。前端不应该直接访问数据库。 API负责写入和读取使用的任何数据持久性基础结构。在许多更大的现实世界系统中,前端和API之间甚至还有一个额外的BFF层,进一步将前端和DB分开。