jsons中集合的最佳实践:array vs dict / map

时间:2018-06-18 13:28:20

标签: python json

我需要使用json格式通过api调用将python后端中的数据传递到前端。在python后端,数据是字典结构,我可以轻松地直接转换为json。但我应该吗?

我的前端开发人员认为答案是否定的,原因与最佳做法有关。

但我挑战:

最好是在python中构造一个json,还是应该转换为其他形式,例如几个数组(在下面的示例中需要)?

或者,换句话说:

与通过jsons接口信息的集合/ dicts / maps /数组相关的管理原则应该是什么?

我已经做了一些谷歌搜索,但我没有遇到太多直接解决这个问题。链接将不胜感激。

(请注意以下示例:当然,如果将数据写入数据库,最好直接访问数据库,但我们假设情况并非如此)

示例:

在后端有一组名为pets的对象: 集合中的每个项目都有一个唯一的pet_id,一些非可选属性,例如namedate_of_birth,一些可选属性registration_certificate_nradopted_from_kennel,一些列表如siblingschildren以及一些对象,如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"
        }
      ]
    }
  }
}

1 个答案:

答案 0 :(得分:2)

JSON格式化是一个有点主观的问题,相关的分歧通常最好在同事之间解决。
话虽如此,在问题中对JSON格式有一些潜在的有效批评,特别是如果我们试图创建一致的RESTful API。

突出的2个痛点:

  1. 地图集合以JSON表示,它不符合JSON标准,或者特别是RESTful。

  2. 所有宠物对象都没有定义id。问题中提到pet_id,但它似乎与宠物对象本身分开维护。如果在问题的pets地图中访问了某个值,那么API的用户必须手动将pet_id添加到提供的宠物对象中,以便在该行下方提供该ID,当完整的JSON可能不再可用时。

  3. 在这种情况下,我们最接近指导标准的是REST architectural styleJSON 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分开。