116

I'm designing a RESTful web service using WebApi and was wondering what HTTP responses and response bodies to return when updating / creating objects.

For example I can use the POST method to send some JSON to the web service and then create an object. Is it best practice to then set the HTTP status to created (201) or ok (200) and simply return a message such as "New Employee added", or return the object that was sent originally?

The same goes for the PUT method. Which HTTP status is best to use and do I need to return the object that was created or just a message? Considering the fact that the user knows what object they are trying to create / update anyway.

Any thoughts?

Example:

Add new Employee:

POST /api/employee HTTP/1.1
Host: localhost:8000
Content-Type: application/json

{
    "Employee": {
        "Name" : "Joe Bloggs",
        "Department" : "Finance"
    }
}

Update existing employee:

PUT /api/employee HTTP/1.1
Host: localhost:8000
Content-Type: application/json

{
    "Employee": {
        "Id" : 1
        "Name" : "Joe Bloggs",
        "Department" : "IT"
    }
}

Responses:

Response with object created / updated

HTTP/1.1 201 Created
Content-Length: 39
Content-Type: application/json; charset=utf-8
Date: Mon, 28 Mar 2016 14:32:39 GMT

{
    "Employee": {
        "Id" : 1
        "Name" : "Joe Bloggs",
        "Department" : "IT"
    }
}

Response with just message:

HTTP/1.1 200 OK
Content-Length: 39
Content-Type: application/json; charset=utf-8
Date: Mon, 28 Mar 2016 14:32:39 GMT

{
    "Message": "Employee updated"
}

Response with just status code:

HTTP/1.1 204 No Content
Content-Length: 39
Date: Mon, 28 Mar 2016 14:32:39 GMT
5
  • 3
    Good question, but using the term "best-practice" is sort of taboo on this site meta.programmers.stackexchange.com/questions/2442/… You might just want to re-word the question. meta.programmers.stackexchange.com/questions/6967/…
    – Snoop
    Mar 28, 2016 at 14:59
  • 4
    As a bit of a follow-up, would it be a good idea to have a flag in the request so that (for example) a mobile application can get the whole object returned when on WiFi, but only the ID when using cellular data? Is there a header that should be used for that to avoid polluting the JSON?
    – Andrew
    Mar 28, 2016 at 20:46
  • 1
    @AndrewPiliser Interesting idea, although I personally think it's just best to pick one approach and stick to it. Then as your application develops or becomes more popular, optimise it
    – iswinky
    Mar 29, 2016 at 7:17
  • @AndrewPiliser your idea is very similar to the Postgresql UPDATE/INSERT ... RETURNING variant for SQL. It's extremely handy, especially as it keeps the submission of new data and request for the updated version atomic.
    – beldaz
    Jul 10, 2018 at 10:40
  • There's a proposal to use Prefer header as @Andrew suggested to advise server what to return rfc-editor.org/rfc/rfc8144.html
    – imel96
    Nov 24, 2021 at 3:54

8 Answers 8

76

As with most things, it depends. Your tradeoff is ease of use versus network size. It can be very helpful for clients to see the created resource. It may include fields populated by the server, such as last-creation-time. Since you appear to be including the id instead of using hateoas, clients will probably want to see the id for the resource they just POSTed.

If you don't include the created resource, please do not create an arbitrary message. The 2xx and Location fields are enough information for clients to be confident that their request was properly handled.

3
  • +1 The hateoas objective of not letting the client compose the uri's can also be achieved by by allowing the client to fill in server provided URL templates with specific ID's. Yes, the client "composes" but only in a "fill in the blanks" kind of way. While not pure HATEOAS it achieves the objective and makes working with objects that have a (large) number of "action" uri's a bit less bandwidth sensitive, not to mention when you put those objects in a (largish) list. Mar 29, 2016 at 11:26
  • 12
    +1 on the "please do not create an arbitrary message" advice Jun 13, 2017 at 20:12
  • Does the "no arbitrary message" focus on string messages or any return value that is not the created resource? I'm focusing on cases where we return the id of the created resource (but not the resource itself) and was wondering where this fits in.
    – Flater
    Sep 4, 2019 at 7:40
26

I would always send back the payload in case of both POST and PUT.

In case of POST you might create the entity with an internal ID or a UUID. Hence it makes sense to send back the payload.

Similarly in case of PUT, you might ignore some fields of the user (immutable values, say), or in case of a PATCH, the data might have been changed by other users as well.

Sending the data back as it was persisted is always a good idea and definitely doesn't harm. If the caller has no need for this returned data, then he/she won't process it but will just consume the statusCode. Else they can use this data as something to update the UI with.

It's only in case of a DELETE that I wouldn't send back the payload and would do either a 200 with a response content, or a 204 with no response content.

Edit: Thanks to some comments from below, I am rewording my answer. I still stand by the way I design my APIs and send back responses but I think it makes sense to qualify some of my design thoughts.

a) When I say send back the payload, I actually meant to say send back the data of the resource, not the same payload that came in the request. Ex: if you send a create payload, I may in the backend create other entities such as UUID and (maybe) timestamps and some (graph) connections even. I would send all this back in the response (not just the request payload as is - which is pointless).

b) I wouldn't send back responses in case the payload is very large. I've discussed this in the comments, but what I would like to caveat is that I would try my best to design my APIs or my resources such that it doesn't have to have very large payloads. I would try to break down the resources into smaller and manageable entities such that each resource is defined by 15-20 JSON attributes and not larger.

In the case that the object is very large or the parent object is being updated, then I would send back the nested structures as hrefs.

Bottom line is I would definitely try to send back the data that makes sense for the consumer / UI to process immediately and be done with an atomic API action rather than have to go and fetch 2-5 more API just to update the UI post the creation / update of the data.

Server to server APIs might think differently about this. I am focusing on APIs that drive a user experience.

10
  • 1
    I can see many situations where sending back the entire payload is a bad idea, when the payload is large.
    – beldaz
    Jul 10, 2018 at 10:42
  • 2
    @beldaz completely agree. YMMV based on the design of the REST API. I generally avoid very large objects and break it down into a series of sub-resources / PUTs. If the payload is very large there are better ways to do this, and therein you would want to do HATEOAS (like Marjan says above) where you return the reference to the object instead of the object itself.
    – ksprashu
    Jul 11, 2018 at 11:20
  • 2
    @ksprashu: "Hence it makes sense to send back the payload" - I find this is a bad idea, because thus a resource can be obtained in many ways: via GET, as a response of POST, as a response of PUT. It means that client obtains 3 resources with potentially different structure. Where as if you would return only URI (location), without body, then the only way to obtain a resource would be GET. This would make sure that client always obtains consistent responses.
    – mentallurg
    Sep 3, 2019 at 0:31
  • 2
    When does it matter then? It matters, when you have 30 - 50 services and a team of 8-10 developers who develop and support these services. If you have no unified approach, this can lead to problems. For instance if for small objtecs your return these objects in the response of POST and for bigger objects you return URI, then nobody in the team will exactly know when what to expect from which service: Does it return a created object? Does it return a URI?
    – mentallurg
    Sep 4, 2019 at 20:49
  • 2
    Another point: If you return an object in POST (also in PUT, PATCH), it can be that is has structure (slightly or essentially) different from what GET returns. May be you forsgot to set some attributes that are set in the GET response. And if you change the response object in the future (because customer permanently gives you new requirements that needs some extention of the object structure), you will have to find all methods that return this object type and extend them in a similar way. This means much more work and more chances to introduce new bugs.
    – mentallurg
    Sep 4, 2019 at 20:49
25

Personally, I always return only 200 OK.

To quote your question

Considering the fact that the user knows what object they are trying to create / update anyway.

Why add extra bandwidth (which might have to be paid for) to tell the client what it already knows?

7
  • 1
    That's what I was thinking, if it's invalid you can return validation messages, but if it's valid and gets created / updated then check the HTTP status code and show the user a message e.g "Hooray" based on that
    – iswinky
    Mar 29, 2016 at 11:29
  • 3
    See stackoverflow.com/a/827045/290182 regarding 200/204 No Content to avoid confusing jQuery and the like.
    – beldaz
    Jul 10, 2018 at 10:44
  • 8
    I'd like to challenge the assumption the client knows which object is being updated. I work in mobile and a pattern is to decouple requests from responses (this makes life much easier in an asynch paradigm). So, ideally, a PUT request returns the updated object and I just replace it on the UI. Otherwise, I have to keep track of which object is awaiting a response.
    – FinalFive
    Mar 9, 2020 at 12:52
  • 14
    Your user might post a partial object with only a few of the fields set. The returning object would have finished the object with generated ID's and the like. E.g., you might post {"full_name": "Joe Doe"} to /user, and get {"id": 42, "first_name": "Joe", "last_name": "Doe", "full_name": "Joe Doe"} in return. Here is the same concept in a API design book: apihandyman.io/… Mar 21, 2020 at 16:41
  • 5
    The reason to return an object, because in most of the cases client will pass a limited list of arguments, ex: title, description. And the server will create id, created date, author and etc. But it depends on usecase
    – Ievgen
    Oct 9, 2020 at 7:46
22

Referencing to the link RFC standards, you should return 201(created) status on successfully storing the request resource using Post. In most of the applications the id of the resource is generated by the server itself, so it is good practice to return the id of the created resource. Returning the whole object is the overhead for Post request. Ideal practice is to return the URL location of the newly created resource.

For example you can refer to the following example that saves the Employee Object into the database and returns the URL of the newly created resource object as a response.

@RequestMapping(path = "/employees", method = RequestMethod.POST)
public ResponseEntity<Object> saveEmployee(@RequestBody Employee employee) {
    int id = employeeService.saveEmployee(employee);
    URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(id).toUri();
    return ResponseEntity.created(uri).build();
}

This rest endpoint will return the response as:

Status 201 - CREATED

Header Location →http://localhost:8080/employees/1

6
  • 1
    Nice and clean - gonna follow this from now and beyond Aug 23, 2019 at 15:56
  • Regarding the absolute URL shown in the example above, it's perfectly OK, per the RFC, Location section 7.1.2, to return a relative URL. E.g., /employees/1
    – Rich
    Mar 22, 2020 at 20:35
  • I think its better to return a relative url, also without versioning prefix. The consumer might want to look up the object on a differently versioned endpoint.
    – The Fool
    Dec 18, 2021 at 19:48
  • 1
    I don't understand why would you return an absolute/relative url in the first place. Just return the id of the resource, and the client side should know how to retrieve it. I see that returning a resource url (absolute or relative) is redundant/pointless.
    – Alan Deep
    May 12, 2022 at 19:31
  • The location header is a good option to returning the created resource. However, as the client often just wants the id and not the url, it makes sense to pass it in the body as json/xml, with conventions according to the API. Headers may be stripped by proxies.
    – user13796
    Jan 19 at 15:33
3

I would make a payload in the return body conditional to a HTTP parameter.

More often than not it is best to return some sort of content back to the API consumer to avoid unnecessary round trips (one of the reasons why GraphQL exists.)

As a matter of fact, as our applications become more data-intensive and distributed, I try observe this guideline:

My Guideline:

Any time there's a use case that demands a GET immediately after a POST or PUT, that is a case where it might be best to simply return something in the POST/PUT response.

How this is done, and what type of content to return back out of a PUT or POST, that's application specific. Now, it would be interesting if the application could parameterize the type of "content" in the response body (do we want just the location of the new object, or some of the fields, or the entire object, etc.)

An application could define a set of parameters a POST/PUT can receive to control the type of of "content" to return in the response body. Or it could encode some sort of GraphQL query as a parameter (I can see this being useful but also become a maintenance nightmare.)

Either way, it seems to me that:

  1. It is OK (and most likely desirable) to return something in a POST/PUT response body.
  2. How this is done is application-specific and almost impossible to generalize.
  3. You do not want to return large-size "context" by default (traffic-noise that defeats the whole reason of moving away from POST-followed-by-GETs.)

So, 1) do it, but 2) keep it simple.

Another option I've seen is people creating alternative end points (say, /customers for POST/PUT that return nothing in the body and /customer_with_details for POST/PUT to /customers, but that return something in the response body.)

I would avoid this approach, though. What happens when you legitimately need to return different type of content? One endpoint per content type? Not scalable or maintainable.

0

Allow the POST endpoint to receive a config setting in the payload returnCreatedResource and accept a true/false value of your preference. If true return the created resource, else don't.

Then the client can decide based on their scenario. Most of the time it's the client's application which is the determining factor of needing the resource or not.

You can't possibly know a client's requirements, no matter how your API or App is configured or what scenario you think may be a time to return the resource or not. Yes ok there will be some scenarios where for some reason created resource must be or must not be returned, etc. But for most APIs, the client being able to choose is by far the best option.

2
  • How would you implement this on the backend controllers? In strongly-typed frameworks it is not a good practice to have single method return multiple result types. You could have generic 'object' response type which would contain all the data you need for all the cases, but this makes code less readable and harder to maintain. Mar 3 at 15:01
  • 1
    @ElectroBuddha if configValue is true return body, else empty body. It's not multiple result types, it's either with or without response body, and the body is always the same if present. I'm in no way suggesting config/options in the request to get different response body data, that's just fiddly, and is what filters are for.
    – James
    Mar 5 at 18:46
0

It's easy: when you have created an object (on the server), simply return a "handle" (or "id") to the object that you have just created. The client can refer to this "handle" to request whatever future information is needed.

And of course, since the possibility exists that this "handle" will never again be referred to, provide some sort of "drop-dead timestamp" and a "garbage collection sweeper."

0

Just returning the object is pointless. The caller has the object already. What you should do is return a status 200 or 201 for “created”, and any information that you have created new on the server. Typically that would be some Id. It could also be any information that wasn’t given and was filled with default values, or data that was corrected (or were limitations of the server were applied, for example if a database doesn’t support full Unicode and Mrs. Zoë was “corrected” to “Zoe”.

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