1

I am trying to create a Put endpoint using rest. Let's say that under the link

/addresses/12345

I am trying to add a new address (if that id doesn't exist) or I'm trying to update it if it does already exist.

My application has several layers Controllers, Services, Models and Repositories. Given the fact that the business layer decides if an update or an add is required (this logic takes place in the service layer and below), how would the controllers be able to find out if an update or an add happened and return the correct status codes (201 for resource created, 204 if just an update has occured)?

My only ideas are to return some sort of result object, but that doesn't feel particularly correct. For the cases where the service methods are not void, they usually return DTOs.

LE: I think I didn't express myself correctly to what the use case is (my example might be a bit stretched). The address resource already has an id, this is why I am not doing a post. Imagine the following endpoint:

/streets/{streetId}/addresses/{addressId}

Here I am trying to add an address with a particular id as a subresource to a street. The reason for which I am not using Post in such a case is because I am not creating a new address and the existing one presumably exists with that same id and can be found at

/addresses/12345

Consequently, for adding such a resource to a particular street, would it still make sense to post it? In my mind, this is where a Put is required, as you wouldn't want to randomly generate different ids for addresses.

  • What is "12345"? Isn't it your address id ? If so, we are talking about existing item and you need to update, not add. I don't get what you ask exactly. Don't you want to use Post method? – Engineert Apr 16 at 8:36
  • 2
    12345 is the id indeed, but if you take a look at Put, you can use that to also create a resource if it doesn't exist and you know the id beforehand, which is my case. – Mike Apr 16 at 8:47
2

Both URLs can be considered an "update" and a PUT is fine. Consider the following requests:

PUT /streets/5/addresses/82 HTTP/1.1

The address Id is specified, so this request links an existing address to an existing street. Perfectly allowable given a PUT.

PUT /streets/5/addresses HTTP/1.1

The request above does not supply an address Id. Presumably we are creating a new address and linking it to street #5 at the same time. Again, PUT is appropriate since we are updating the street as well.

If the context of the URL changes, then I think it justifies switching from a PUT to a POST. For instance:

POST /addresses HTTP/1.1

The request above does not specify an address Id, and this address is not a sub resource of another resource. You are legitimately doing an INSERT here, so a POST request is correct.

PUT /addresses/82 HTTP/1.1

The request above is appropriate whether you are updating an existing address, or creating a new address and specifying the Id.

More info: PUT vs. POST in REST on StackOverflow.

Given this, a PUT /streets/{streetId}/addresses should just return a 200 OK response, even though it is inserting an address, it is updating a street.

A PUT /streets/{streetId}/addresses/{addressId} should also return a 200 OK response.

Does the client really need to know that a new address object was created? Probably not.

Just return a 200 OK response in either case, so there is no need to return any sort of response code from the service layer.

  • It is valid per the spec to create a resource using PUT if you have the ID. You answer appears to assume that resources may only be created using POST. – Eric Stein Apr 16 at 13:45
  • I edited my question to reflect why I am doing a PUT rather than a POST, and as Eric said, it should be acceptable by the spec – Mike Apr 16 at 14:18
  • Ok. No time at the moment, but I may end up re-rewriting my answer. – Greg Burghardt Apr 16 at 15:51
  • @EricStein: After Mike clarified the use case, I've rewritten my answer (yet again). – Greg Burghardt Apr 17 at 14:36
  • Thank you, I think I get it now :) – Mike Apr 18 at 8:07
3

The status code is largely metadata describing the response-body, which is usually a representation of the status of the action. For example, 204 No Content specifically indicates that the representation is zero bytes long.

Which changes your question slightly -- where does this status of the action come from when your methods return void?

The usual answer is that the capabilities required for each case are passed into the methods (aka call backs).

void doTheThing(onNew, onUpdate) {
    // ... do all of the actual work, then ...
    if (weJustAddedSomethingNew) {
        onNew( /* args */);
    } else {
        onUpdate( /* args */);
    }
}

Pryce and Freeman's Growing Object Oriented Software describes techniques for developing protocol designs in this way.

The callbacks themselves would then have the responsibility for constructing the headers and payload for the HTTP response from the information provided to them by the domain model.

  • It may be worth noting that the call back does not have to be passed when the void method is called. It could have been configured previously in the methods object state and be waiting to be used when called. This way the calling code doesn't have to understand what you're talking to at all. All the calling code has to know is: do it now. – candied_orange Apr 17 at 18:46
3

You are 100% to use a PUT here, you have a URI already so PUT is the correct verb to use.

The client don't actually have to care though if the server creates something on its end (a db record, or a file on the file system for example).

The client has already "created" the resource, it is simply telling the server to update itself with this current representation of the resource. The server might have to do something because to persist this resource because it has never seen it before, but from a REST view point that is not the creation of the resource. The resource was created by the client when it give the data a URL.

Remember a resource is not some db record or file on a file system. It is an abstract concept and a client can create one just as much as a server can. If you are not sure where the resource was created the key to knowing what created the resource is what determine its URI and set its content. In this case the client did.

The client shouldn't care what the server has to do to persist that resource on the server side. As far as the client is concerned the resource was created the moment it created it (probably when it figured out what URI it should have) and what the server has to do to persist it on the server's end is not a concern of the client.

So 200 OK is perfectly valid here, unless you have some particular reason that client needs to know how the server persisted the resource on the server side, which is kinda unRESTful so I would have to know the specific reason the client needs to know this.

201 is for situations where the server creates resources the client does not yet know about, and the server needs a way to tell the client what these new resources are (ie pass the new URI to the client).

  • "None of our business which" Exactly. It is actually a REST design smell if the client is concerned about what exactly the server did in order to carry out the state transfer as this introduces coupling between client and server implementation which REST is designed to avoid. – Cormac Mulhall Apr 17 at 15:05
  • Oops meant create or update. Silly me. Lets try this again. – candied_orange Apr 17 at 15:10
  • I like the point you're making about abstraction here. It's far too easy to think of the 4 rest verbs as simply CRUD over the web. No, we should neither know nor care what the DB is doing. So PUT can map to create or update. None of our business which. Just put this somewhere. – candied_orange Apr 17 at 15:14
  • If 201 is for situations where the server creates resources the client does not know about, when would that apply? Because for PUT, from what I can see, you always need to specify the id of the created resource. That's what confuses me. Other than that, it all makes sense :) Edit: I read Greg's response from further below and that explains a bit more when a 201 should be returned from PUT – Mike Apr 18 at 8:03
  • It would mostly apply as a response to a POST that resulted in the creation (by the server) of some new resources by the server. The 201 response then contains the URI of the newly created resources. But any request that results in creation of new resources by the server that the client needs to care about should involve a 201 response. Say for example the client PUTs an update to a resource representing me that changes my status to 'dead'. That may results in the creation of a death cert resource by the server that is then passed back to the client via a 201 response. – Cormac Mulhall Apr 19 at 9:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.