193

Suppose I write a REST service whose intent is to add a new data item to a system.

I plan to POST to

http://myhost/serviceX/someResources

Suppose that works, what response code should I use? And what content might I return.

I'm looking at the definitions of HTTP response codes and see these possibilities:

200: Return an entity describing or containing the result of the action;

201: which means CREATED. Meaning *The request has been fulfilled and resulted in a new resource being created. The newly created resource can be referenced by the URI(s) returned in the entity of the response, with the most specific URI for the resource given by a Location header field. The response SHOULD include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. *

The latter sounds more in line with the Http spec, but I'm not at all clear what

The response SHOULD include an entity containing a list of resource characteristics and location(s)

means.

Recommendations? Interpretations?

Mark Stewart
  • 2,046
  • 4
  • 22
  • 32
djna
  • 54,992
  • 14
  • 74
  • 117

7 Answers7

136

The idea is that the response body gives you a page that links you to the thing:

201 Created

The 201 (Created) status code indicates that the request has been fulfilled and has resulted in one or more new resources being created. The primary resource created by the request is identified by either a Location header field in the response or, if no Location field is received, by the effective request URI.

This means that you would include a Location in the response header that gives the URL of where you can find the newly created thing:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597

Response body

They then go on to mention what you should include in the response body:

The 201 response payload typically describes and links to the resource(s) created.

For the human using the browser, you give them something they can look at, and click, to get to their newly created resource:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: text/html

Your answer has been saved! 
Click <A href="/a/36373586/12597">here</A> to view it.

If the page will only be used by a robot, the it makes sense to have the response be computer readable:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/xml

<createdResources>
   <questionID>1860645</questionID>
   <answerID>36373586</answerID>
   <primary>/a/36373586/12597</primary>
   <additional>
      <resource>http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586</resource>
      <resource>http://stackoverflow.com/a/1962757/12597</resource>
   </additional>
</createdResource>

Or, if you prefer:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/json

{ 
   "questionID": 1860645, 
   "answerID": 36373586,
   "primary": "/a/36373586/12597",
   "additional": [
      "http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586",
      "http://stackoverflow.com/a/36373586/12597"
   ]
}

The response is entirely up to you; it's arbitrarily what you'd like.

Cache friendly

Finally there's the optimization that I can pre-cache the created resource (because I already have the content; I just uploaded it). The server can return a date or ETag which I can store with the content I just uploaded:

See Section 7.2 for a discussion of the meaning and purpose of validator header fields, such as ETag and Last-Modified, in a 201 response.

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/23704283/12597
Content-Type: text/html
ETag: JF2CA53BOMQGU5LTOQQGC3RAMV4GC3LQNRSS4
Last-Modified: Sat, 02 Apr 2016 12:22:39 GMT 

Your answer has been saved! 
Click <A href="/a/36373586/12597">here</A> to view it.

And ETag s are purely arbitrary values. Having them be different when a resource changes (and caches need to be updated) is all that matters. The ETag is usually a hash (e.g. SHA2-256). But it can be a database rowversion, or an incrementing revision number. Anything that will change when the thing changes.

Community
  • 1
  • 1
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • So far you're response seems most sensible. I'm a little anxious about the ontology of the response, but aside from that, it seems like the most mature interpretation of the spec. I am curious if there's any sort of lightweight "responsive" way to handle human/machine output. but mostly I'm intrigued by your "caching your own input" suggestion. Most web apps I know are not going to create a 1:1 version of the resource. Even if it's something trivial like normalizing capitalization of a string. Isn't it a bit dodgy to treat your submitted version as the version the etag was created against? – Anthony Aug 30 '16 at 12:57
  • 1
    @Anthony, caching: it could be a kind of 1:1 file storage application. Compare e.g. WebDAV PUT & POST. Huge files to be handled. – kxr May 12 '17 at 14:00
  • @Anthony It's up to you if you want to return an ETag back to the client. If the content the client *just* uploaded is not what you saved, then don't return the ETag. It's your flexibility and your choice. – Ian Boyd May 12 '17 at 18:14
  • Why are your responses missing the Content-Length? – Vinnie Falco Jan 09 '18 at 15:07
  • 1
    @VinnieFalco This is an answer about the 201 response code . Content-Length has been elided for expository purposes. – Ian Boyd Jan 11 '18 at 20:34
119

In a few words:

  • 200 when an object is created and returned
  • 201 when an object is created but only its reference is returned (such as an ID or a link)
Stéphane Bruckert
  • 21,706
  • 14
  • 92
  • 130
  • 5
    Source for this? – sudo soul Oct 23 '18 at 20:03
  • 4
    This what I understand from https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html and https://httpstatuses.com/201 – Stéphane Bruckert Oct 23 '18 at 21:24
  • 14
    After reading https://tools.ietf.org/html/rfc7231#section-6.3.1, I agree with this understanding - I suppose I was asking moreso how you arrived at it. But now in my understanding... 200 = resource created and returned | 201 = resource created and reference is returned | 204 = resource created and no payload returned – sudo soul Oct 24 '18 at 20:04
  • @sudosoul Would the location header also be returned with a 204, as it's in a 201? – pmiguelpinto90 Sep 15 '20 at 15:44
  • 2
    @MiguelPynto According to RFC 7231, I would say no, that the location header should not be returned with a 204. Although, a 204 response can include header metadata that ultimately implies the request was successful. Check the link I posted to RFC 7231 and see the paragraph on 204. – sudo soul Sep 15 '20 at 16:41
94

I think atompub REST API is a great example of a restful service. See the snippet below from the atompub spec:

POST /edit/ HTTP/1.1
Host: example.org
User-Agent: Thingio/1.0
Authorization: Basic ZGFmZnk6c2VjZXJldA==
Content-Type: application/atom+xml;type=entry
Content-Length: nnn
Slug: First Post

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
</entry>

The server signals a successful creation with a status code of 201. The response includes a Location header indicating the Member Entry URI of the Atom Entry, and a representation of that Entry in the body of the response.

HTTP/1.1 201 Created
Date: Fri, 7 Oct 2005 17:17:11 GMT
Content-Length: nnn
Content-Type: application/atom+xml;type=entry;charset="utf-8"
Location: http://example.org/edit/first-post.atom
ETag: "c180de84f991g8"  

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
  <link rel="edit"
      href="http://example.org/edit/first-post.atom"/>
</entry>

The Entry created and returned by the Collection might not match the Entry POSTed by the client. A server MAY change the values of various elements in the Entry, such as the atom:id, atom:updated, and atom:author values, and MAY choose to remove or add other elements and attributes, or change element content and attribute values.

Chandra Patni
  • 17,347
  • 10
  • 55
  • 65
  • 9
    Returning the created resource may be a bit much, if the resource is in the gigabytes magnitude... – Tor Valamo Dec 27 '09 at 06:04
  • 12
    Agreed! That's the optimization of necessity-- but you don't want to do it prematurely. It's important to design in Restful spirits and make exceptions only when they are necessary. – Chandra Patni Dec 27 '09 at 08:18
  • 4
    @ChandraPatni, **Atom is dead**. Need better examples. – Pacerier Oct 08 '15 at 10:51
  • 16
    Atom may be dead, but the spirit of the example is still spot on. – Ashimema Oct 27 '15 at 06:09
  • What is the key difference between this response and a 200 response? As far as I can tell, the differences are the Status code itself, and the inclusion of the `Location` header. Seems like basically 200 + "here's a URL for later!" . Is that the gist? – Anthony Aug 30 '16 at 12:38
  • 2
    My original interpretation of the 201 response was more like "hey, you wanted to create a resource, but based on context, you either weren't interested in the final result, or have write access but not read access to this resource. In either case, all you need before returning to the main collection is the URL of the created resource. As evidence it was created." Anything beyond that seems like a 200 response, essentially. Unless the RFC had something else in mind. – Anthony Aug 30 '16 at 12:42
  • upvoted! if you add a resource via PUT to a database and if the item is not added because it already exists do you still return 201? – PirateApp Jun 14 '20 at 12:23
  • 1
    @PirateApp "422 Unprocessable Content" or "204 No content" looks like a better fit for that. 422 would mean server gets your request, but not able to create resource/process instructions (https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422) – Ola Jun 24 '23 at 11:21
39

Check out HTTP: Method Definitions: POST.

The action performed by the POST method might not result in a resource that can be identified by a URI. In this case, either 200 (OK) or 204 (No Content) is the appropriate response status, depending on whether or not the response includes an entity that describes the result.

If a resource has been created on the origin server, the response SHOULD be 201 (Created) and contain an entity which describes the status of the request and refers to the new resource, and a Location header (see section 14.30).

Community
  • 1
  • 1
ma11hew28
  • 121,420
  • 116
  • 450
  • 651
18

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19

It's just a colon delimited key-value.

ETag: "xyzzy"

It can be any type of text data - I generally include a JSON string with the identifier of the item created. The ease of testing alone makes including it worthwhile.

ETag: "{ id: 1234, uri: 'http://domain.com/comments/1234', type: 'comment' }"

In this example, the identifier, the uri, and type of the created item are the "resource characteristics and location".

Tempire
  • 2,290
  • 19
  • 14
  • 3
    You are saying that an ETag corresponds to an *entity containing a list of resource characteristics and location(s)*. I can see that your suggestion is good, very much agree with your point about testing. However I don't see how this fits with "a list of resource characteristics and locations". – djna Dec 26 '09 at 08:22
  • The "list of resource characteristics and locations" would be the content of whatever data structure provided. A more strict implementation would be for the JSON structure to include the resource uri and maybe the type of resource that was created. I'll adjust the answer as such. – Tempire Dec 27 '09 at 01:20
  • 7
    Specify the issues, so that people may learn. Otherwise, the comment is just hand-waving. – Tempire Oct 21 '13 at 23:00
  • @SimonGibbs What issues? – MEMark Jul 04 '14 at 17:41
  • 2
    While it's strictly correct per the spec, it recommends a highly unusual implementation option. Also it does not actually answer the question at the top of the page (or else it does so by mixing up the words ETag and entity). The answer with 43 votes is probably better. – Simon Gibbs Jul 08 '14 at 15:19
  • Your use of `ETag` breaks the intent, which is an alternative to `Last-Modified`, i.e. detecting if the resource has changed. If comment 1234 is edited/updated, your etag remains unchanged, thus the client will not receive the updated version when requested. – nilskp Nov 21 '16 at 20:20
  • The specification doesn't list this intent; what is the specification for if not for intent? It may be convention to use it for Last-Modified, but the specification is much more flexible. – Tempire Mar 13 '17 at 23:43
  • Although this is the accepted answer, it is actually plain wrong. It is correct that you MAY use an ETag for this purpose but the answer makes it look like that this is the generally accepted way to interpret the standard - but it isn't at all. You might just return a URL, for example - and doing so in the Location header is even stated in the RFC as a possibility, and it does do just what the spec says " an entity containing a list of resource characteristics and location(s)". – nepdev Jun 21 '17 at 03:55
  • It's not wrong. It's may not be common usage, but to be wrong means the specification would have to explicitly state what it should be used for. What you really mean is, "I don't use it for anything but x, therefore you shouldn't either". If we're just stating opinions as factually correct, then I'm going to say limiting the usage to Last-Modified is wrong. – Tempire Jun 23 '17 at 22:11
  • RFC 7232 (one of several which collectively obsolete RFC 2616 - this original question and answer is quite old!) re-enforces that the ETag value is intended to be an opaque indentifier. That is, you as the client shouldn't be attempting to interpret it, just re-present it back in a later request. – jrg Aug 22 '17 at 17:19
  • Including a static (never-changing) ID in ETag may cause the resource unintentionally cached. See answer below https://stackoverflow.com/a/36373586/3622300 – Guney Ozsan May 05 '20 at 07:50
1

The output is actually dependent on the content type being requested. However, at minimum you should put the resource that was created in Location. Just like the Post-Redirect-Get pattern.

In my case I leave it blank until requested otherwise. Since that is the behavior of JAX-RS when using Response.created().

However, just note that browsers and frameworks like Angular do not follow 201's automatically. I have noted the behaviour in http://www.trajano.net/2013/05/201-created-with-angular-resource/

Archimedes Trajano
  • 35,625
  • 19
  • 175
  • 265
-1

Another answer I would have for this would be to take a pragmatic approach and keep your REST API contract simple. In my case I had refactored my REST API to make things more testable without resorting to JavaScript or XHR, just simple HTML forms and links.

So to be more specific on your question above, I'd just use return code 200 and have the returned message contain a JSON message that your application can understand. Depending on your needs it may require the ID of the object that is newly created so the web application can get the data in another call.

One note, in my refactored API contract, POST responses should not contain any cacheable data as POSTs are not really cachable, so limit it to IDs that can be requested and cached using a GET request.

Archimedes Trajano
  • 35,625
  • 19
  • 175
  • 265