0

I've read put-vs-post-in-rest through, and I know that PUT is for create and update specific resource with identifier given specifically in URL.

But if I'm going to strict the "update" operation with If-Match (which means user MUST provide valid ETag to update the resource), given that PUT is also used to create named resource, (which do not require If-Match), then the API will have to guess whether the PUT request means to update or to create by whether If-Match header is provided.

I know this can be done but I think it's weird. Are there other (more reasonable) ways to do this (by not using PUT maybe)?

Thanks.

UPDATE:

Here is my scenario for now:

# create the resource the first time
curl -X PUT -d '{"foo": "bar"}' /resource/r_id 

# the resource already exists, so this will fail with a 4xx error
curl -X PUT -d '{"foo": "bar2"}' /resource/r_id 

# must provide valid If-Match to make updates work
curl -X PUT -H 'If-Modefied: myetag' -d '{"foo": "bar2"}'  /resource/r_id

# what makes it confusing is this:
# user want to make a new record, but /resource/r_id2 in fact exists
# the API will return an error message, should it be
# "creation failed -- already exist" or "update failed -- ETag not provided"?
curl -X PUT -d '{"foo": "bar"}' /resource/r_id2

It's not that this can't be done, it's just that I think this design(with PUT for both ETag-controlled update AND named creation) might be confusing, I personally think it's better if I use different vocabulary (not just PUT), but, I'm here asking what's the reasonable and RESTful way I can do this.

Community
  • 1
  • 1
tdihp
  • 2,329
  • 2
  • 23
  • 40

3 Answers3

2

You could secure the PUT-to-create with "If-None-Match: *", see http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p4-conditional-26.html#rfc.section.3.2.p.7.

Also, you may want to consider using http://greenbytes.de/tech/webdav/rfc6585.html#status-428.

Julian Reschke
  • 40,156
  • 8
  • 95
  • 98
1

You may try to mimic well designed REST APIs.

For this feature, CouchDB designers chose to emit 409 Conflict as the status, and {"error":"conflict","reason":"Document update conflict."} as the body.

Nota bene: Remove "document" of course since it is specific to the application.

Aurélien Bénel
  • 3,775
  • 24
  • 45
  • So I should just put "creation failed" and "update failed" together, like, "creation failed or update failed" would be okay? – tdihp Apr 03 '14 at 07:10
  • The most important thing is using the standard HTTP status. The body is just here to help clients implementors. I think they can survive the general phrase "Update conflict" for both failed creation and update. Moreover the "creation" failed because of an "update" conflict. – Aurélien Bénel Apr 03 '14 at 15:46
0

You don't need to restrict the update with If-Match. When you get a PUT, check your datastore. If a resource with the given id doesn't exist yet, create it. If it does, update it to have the given values.

What If-Match buys you is making sure that the resource hasn't changed in the datastore. You're trying to avoid this:

client 1: GET /resources/1
client 2: GET /resources/1
client 2: PUT /resources/1 with updates
client 1: PUT /resources/1 with updates
Eric Stein
  • 13,209
  • 3
  • 37
  • 52
  • Yes, I AM buying what If-Match gives, that's the prerequisite here. I've updated my question with samples, please check, thanks. – tdihp Apr 03 '14 at 06:02