Reputation: 3595
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
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
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
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
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