ktusznio
ktusznio

Reputation: 3595

Creation of REST resources: compose or separate?

Suppose I need to create a shipment to a customer and that shipment requires an address. Both resources need to be created.

In REST design, which approach is preferred? And why?

# One request that in-lines the address.
POST /shipments    
{
  "shipment": {
    "customer_id": 1,
    "address": {
      "city": "Toronto",
      ...
    }
  }
}

vs

# Two requests, first creating the address, then passing an id.
POST /addresses
{
  "address": {
    "customer_id": 1,
    "city": "Toronto",
    ...
  }
}

POST /shipment
{
  "shipment": {
    customer_id: 1,
    address_id: 100
  }
}

Upvotes: 1

Views: 144

Answers (4)

DenisL
DenisL

Reputation: 328

I believe any modern public API (assume your API is public) design should be derived from the most common use cases and not from internal structure of the code. I.e. your API should be as usable as possible for that use cases. Testability and internal structure are important too, but usability is more important because a developer (actually customer of your service) is much more bothered by how easy to use your API than how complex design of internals is.

So, I think, it is impossible to provide certain answer to your question unless your provide a set of the most common use cases for your API. Then, you should consider asking developers who know nothing about your API how they would like to complete the use cases. The most common answers will show the best approaches.

Upvotes: 0

Mike Dunker
Mike Dunker

Reputation: 1990

It is important to think first of the business and usability implications, and then use RESTful design practices to implement a reasonable solution.

In your example, if you only implement separate REST calls for creating the shipment and embedded address, the app developer will be unable to create the shipment in an atomic fashion. If creation of the shipment is successful, and then the creation of the address fails or the network connection is lost, you end up with incomplete data at your backend. Even if the app developer is able to roll back the change, you are adding significant complexity to the app design.

So for the create, I would allow the address to be included in the shipment, or force it to be included if a shipment without an address violates your business rules. Other decisions (whether to create separate calls for updates or update all shipment fields at the same time or support both, for example) will also often be suggested by business rules and application design.

Upvotes: 2

Ming Chan
Ming Chan

Reputation: 1948

From your descriptions, you want to manipulate/manage two “REST” resources: shipment and address.

Also you're implying that address is a sub-resource under shipment

Use-case-1: to create a shipment with address info

POST /shipments/
BODY: {address {<<address info}}
RETURN: {shipment-id}

Use-case-2: to create a shipment without address info

POST /shipments/
BODY: {}
RETURN: {shipment-id}

Use-case-3: to update a shipment with address info

PUT /shipments/[shipment-id]/address/
BODY: {address {<<address info}}

Use-case-4: if you have use-case to create address independently, you can have

POST /addresses/
BODY: {address-info}
RETURN: {address-id}

Use-case-5: You can update shipment with address-id,

PUT /shipments/[shipment-id]/address/
BODY: {address–id {id-} }

Upvotes: 0

ssedano
ssedano

Reputation: 8432

This is just my opinion. ButI would allow both methods. To do it I would use two different media-types. But if you are using only application/json media type still possible to allow both.

Most languages have automatic de/serializers from json to model objects and back. But YMMV.

Although the two media types approach is optional and have huge implications (as you would be needing to use specific media types for all your representations instead of application/json) I prefer to be explicit. It allows for early discarding of the request (headers gets first to the server and client).

BUT, if you are asking if there is any "preferred" way, it is not AFAIK. One saves you (or the client) a request and a network roundtrip, but the other states more clearly the structure of your API.

Upvotes: 1

Related Questions