RESTful API - 处理嵌套关系

3

假设我正在构建一个处理预约的API。一个预约由医生、患者和一组关心组成。

如果我想创建一个预约,POST数据应该长什么样子?请注意,只有预约会被创建,医生、患者和关心条目已经存在于数据库中。

我有两个选项:

短的版本

{
  doctor_id: 8,
  patient_id: 4,
  cares_ids:
  [1,7]
}

更长的一个

{
  doctor: {
    id: 8,
    name: 'Dr James Brown',
    phone: '107-102-304',
    address: '16th avenue'
  },
  patient: {
    id: 4,
    name: 'Mr Elvis',
    pathology: 'Blah Blah.'
  },
  cares:
  [
    {
      id: 1,
      name: 'Dental cares'
    },
    {
      id: 7,
      name: 'Back pain'
    }
  ]
}

第一个选项感觉更加简洁,因为我们不会发送无用的数据,如姓名和地址等。但第二个选项在我的前端代码中更加自然/语义化。

例如,在我的应用程序中,我只需要执行以下操作:

appointment.doctor = selected_doctor
// Instead of doing
appointment.doctor_id = selected_doctor.id

有没有关于这种情况的 RESTful 最佳实践?
1个回答

2
事实上,您面临的问题是关系问题。OData 提供了一个名为“导航属性”的解决方案来解决这个问题。也许这可以给您一些修复此问题的提示。您可以查看以下链接以获取更多详细信息:http://www.odata.org/getting-started/basic-tutorial/http://www.odata.org/getting-started/advanced-tutorial/ 事实上,这里有几个问题:
- 设计在获取约会时想要拥有的表示形式 - 设计用于创建或更新约会的表示形式 - 设计用于分配(单基数 - “医生”和“患者”)/添加和删除(多基数 - “关心”)与约会相关联的链接的表示形式(例如医生)
我认为,在您的问题中提供的完整表示形式对应于您在获取约会时期望拥有的内容,即约会数据包括医生、患者和关心等关系数据。
这些提示并非将预约与其他元素(如医生和患者)链接所必需的。只有标识符是重要的。我认为您可以为预约创建使用不同的表示方式。在此级别上,设置元素的引用就足够了。因此,您可以使用以下内容:
POST /appointments
{
  doctor-ref: http://.../doctors/8,
  patient-ref: http://.../patients/4,
  cares-ref: [ http://.../cares/1, http://.../cares/7 ]
}

或者

POST /appointments
{
  doctor@metadata.ref: http://.../doctors/8,
  patient@metadata.ref: http://.../patients/4,
  cares@metadata.ref: [ http://.../cares/1, http://.../cares/7 ]
}

同样地,您可以定义其他资源以便在创建约会后更新这些链接而无需发送所有内容。我们可以想象出这样的情况:
  • Single cardinality

    PUT /appointments/<appointmentid>/doctor
    { doctor@metadata.ref: http://.../doctors/8 }
    
  • Multiple cardinality

    POST /appointments/<appointmentid>/cares
    { metadata.ref: http://.../cares/8 }
    DELETE appointments/<appointmentid>/cares
    { metadata.ref: http://.../cares/8 }
    
你可以注意到,你也可以选择不检索预约的所有数据(如果这对你有意义的话)。以下是你可能会看到的不同表示方式:
  • Complete

    {
      doctor: {
        id: 8,
        name: 'Dr James Brown',
        phone: '107-102-304',
        address: '16th avenue'
      },
      patient: {
        id: 4,
        name: 'Mr Elvis',
        pathology: 'Blah Blah.'
      },
      cares:
        [
          {
            id: 1,
            name: 'Dental cares'
          },
          {
            id: 7,
            name: 'Back pain'
          }
       ]
     }
    

    }

  • Parial with links / references

    {
      doctor@metadata.ref: http://.../doctors/8,
      patient: {
        id: 4,
        name: 'Mr Elvis',
        pathology: 'Blah Blah.'
      },
      cares@metadata.ref: [ http://.../cares/1, http://.../cares/7 ]
    }
    

    or

    {
      doctor@metadata.ref: http://.../doctors/8,
      patient: {
        id: 4,
        name: 'Mr Elvis',
        pathology: 'Blah Blah.'
      },
      cares:
        [
          {
            id: 1,
            name: 'Dental cares'
          },
          {
            id: 7,
            name: 'Back pain'
          }
       ]
     }
    

    }

这个功能在OData中对应查询参数$expand
你可以查看这个链接:http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/entity-relations-in-odata-v4。查看"获取相关实体","创建实体之间的关系"和"删除实体之间的关系"部分。它可以为您的表述提供提示。
最后一个问题与构建表示方式相关(例如创建)。我不知道您使用的确切技术,但在Java中,您可以这样做:appointment.doctor = selected_doctor并且稍微调整对象的序列化,以从Doctor实例创建类似于doctor@metadata.ref: http://.../doctors/8的东西。例如,使用Jackson2,它被称为自定义序列化程序(例如,请参见此链接http://www.baeldung.com/jackson-custom-serialization)。
希望对您有所帮助, Thierry

非常感谢您详细的回答!很抱歉回复晚了。我之前不知道OData,现在会去了解一下。谢谢! - gkpo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接