Rest 如何在同一请求中发布两个资源?

Rest 如何在同一请求中发布两个资源?,rest,Rest,我有/公司和/用户资源。我的业务逻辑阻止在没有第一个用户的情况下创建公司。我能想到的唯一办法是: POST /companies { "name": "Harvey's Broiler", "user": { "firstName": "Jojo", "lastName": "Stomopolous", "email": "jojostomopolous@harveysbroiler.com", "password": "password" } }

我有
/公司
/用户
资源。我的业务逻辑阻止在没有第一个用户的情况下创建公司。我能想到的唯一办法是:

POST /companies
{
  "name": "Harvey's Broiler",
  "user": {
    "firstName": "Jojo",
    "lastName": "Stomopolous",
    "email": "jojostomopolous@harveysbroiler.com",
    "password": "password"
  }
}
答复:

{
  "id": 10001,
  "name": "Harvey's Broiler",
  "user": {
    "id": 10002,
    "firstName": "Jojo",
    "lastName": "Stomopolous",
    "email": "jojostomopolous@harveysbroiler.com"
  }
}
{
  "id": 10001,
  "name": "Harvey's Broiler"
}
{
  "id": 10002,
  "firstName": "Jojo",
  "lastName": "Stomopolous",
  "email": "jojostomopolous@harveysbroiler.com"
}
稍后,可以通过以下方式访问它们:

GET /companies/10001
答复:

{
  "id": 10001,
  "name": "Harvey's Broiler",
  "user": {
    "id": 10002,
    "firstName": "Jojo",
    "lastName": "Stomopolous",
    "email": "jojostomopolous@harveysbroiler.com"
  }
}
{
  "id": 10001,
  "name": "Harvey's Broiler"
}
{
  "id": 10002,
  "firstName": "Jojo",
  "lastName": "Stomopolous",
  "email": "jojostomopolous@harveysbroiler.com"
}

答复:

{
  "id": 10001,
  "name": "Harvey's Broiler",
  "user": {
    "id": 10002,
    "firstName": "Jojo",
    "lastName": "Stomopolous",
    "email": "jojostomopolous@harveysbroiler.com"
  }
}
{
  "id": 10001,
  "name": "Harvey's Broiler"
}
{
  "id": 10002,
  "firstName": "Jojo",
  "lastName": "Stomopolous",
  "email": "jojostomopolous@harveysbroiler.com"
}

这是开发人员在设计API时经常遇到的问题

您应该问自己的第一个问题是
公司
用户
资源是否是同一顺序的公民?我所说的顺序,是指它们是否同样重要,它们是否都是您大量使用的资源,并且在您正在构建的系统中具有独立的角色和操作?我的直觉是答案是肯定的。如果答案是否定的,那么
用户
只是表示
公司
创始人的一种方式,您没有问题,只需像之前一样将
用户
作为嵌入对象

然而,如果我的直觉是正确的,你有一些关于
用户
公司
的业务逻辑,我会这样做,把它们分开,放在不同的端点下

如果您需要
用户
来创建
公司
,则可以实现该逻辑。如果试图用缺少的
用户创建
公司
,则返回错误(HTTP响应400或类似于这些行的内容)。当然,应该为用户记录这一点。请求不是这样的:

POST /companies
{
  "name": "Harvey's Broiler",
  "user": 1234
}
人为地混搭在同一请求下创建两个对象只会导致问题。现在您需要返回两个ID的状态(创建了
用户
,但是
公司
失败了?),返回两个ID(如果您还需要添加其他信息、税务详细信息、您获得第三个ID怎么办)等等

公司
一起创建
用户
的唯一有效原因是如果
用户
经常与
公司
一起创建,如果不总是这样,那么您需要减少API调用的数量,因此您只触发一个,但我不确定情况是否如此

如果没有
公司
,您甚至无法拥有
用户
,那么您可以通过两个步骤修改需求或创建
用户
/
公司
。首先激发对
用户
占位符的请求(假设
用户
用户
列表中不可见,它将无效),并且在创建
公司
后,
用户
变为有效和可见,并且允许其他操作。在此之前,没有
用户
,只有它的占位符。对于
公司
,同样的逻辑可以颠倒

还有一件事,我不会去做这种筑巢:

GET /companies/10001/users/10002
首先,编程通常很难(你会得到很多样板文件),这可能是维护的噩梦。您可以将情况推断为:

GET /companies/10001/users/10002/accounts/24314/bank/address
并为创建公司的用户的银行获取银行地址。如果没有必要,我会犹豫是否实施这种方法


也请考虑阅读。如果您需要这种嵌套,它可能会对您有所帮助。事实上,在开始一个新的API时,我会一直鼓励至少考虑HATEOAS原则。

好的,发布两个资源的要点是原子操作。REST不是数据库包装器,我们不能依赖客户机以正确的顺序调用REST。因此,如果您的业务逻辑是“没有用户就无法创建公司”,那么端点应该足够智能,以保护数据不受任何数据集成问题的影响。由于这是发布部分,我看不到HATEOAS对特定逻辑的任何帮助。当然,你必须保护呼叫。我的意思是,我使用的大多数API都有某种时间耦合。对于初学者,通常在调用其他端点之前必须进行身份验证。然而,如果您确实希望将其作为一个请求,请记住,一切都是一种资源。创建一个名为CompanyFoundation的资源,包含属性companyInfo和user,然后像这样尝试。在后端,您可以创建两个实体并存储它们:公司和用户。