Rest api design: POST to create with duplicate data, would-be IntegrityError/500, what would be correct?

17,973

Solution 1

@StevenFisher is correct. 409 Conflict is the correct response.

The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.

For instance, a GET on / might tell a client that they can create users as follows

HTTP/1.1 200 OK
<users href="/">
    <create href="/" method="post">
        <username type="xs:token" cardinality="required"/>
        <password type="password" cardinality="required"/>
    </create>
    ... other hypermedia controls, like search ...
</users>

Following the hypermedia control and trying to create a user with the username "Skylar Saveland" might result in

HTTP/1.1 409 Conflict
<users href="/">
    <create href="/" method="post">
        <username type="xs:token" cardinality="required" 
                  error="The username 'Skylar Saveland' is already taken. Please select another username"/>
        <password type="password" cardinality="required"/>
    </create>
    ... other hypermedia controls, like search ...
</users>

Similarly, trying to create a user without a password might result in

HTTP/1.1 409 Conflict
<users href="/">
    <create href="/" method="post">
        <username type="xs:token" cardinality="required"/>
        <password type="password" cardinality="required" 
                  error="A password must be specified"/>
    </create>
    ... other hypermedia controls, like search ...
</users>

or you might have multiple errors, e.g.,

HTTP/1.1 409 Conflict
<users href="/">
    <create href="/" method="post">
        <username type="xs:token" cardinality="required"
                  error="The username 'Skylar Saveland' is already taken. Please select another username"/>
        <password type="password" cardinality="required"
                  error="A password must be specified"/>
    </create>
    ... other hypermedia controls, like search ...
</users>

NOTE: An appropriate media type will need to be created to go along with the above, which will explain the structure of the hypermedia controls (including the error attributes on the forms) and define the meaning of the various element names (e.g., users, username, password, etc).

Solution 2

#3 is more appropriate. 5xx errors are when there's something wrong with the server. 4xx errors are when something is wrong with the request. In this case, the request is wrong, so a 4xx is more appropriate. Either a 400 or 409.

Or you can do #2, really depends on the context.

Share:
17,973

Related videos on Youtube

Skylar Saveland
Author by

Skylar Saveland

Updated on June 06, 2022

Comments

  • Skylar Saveland
    Skylar Saveland almost 2 years

    I have a normal, basic REST api like:

    /
        GET - list
        POST - create
    
    /<id>
        GET - detail
        PUT - replace
        PATCH - patch
        DELETE - delete
    

    When a POST comes in to /, I usually create an object and make a new id. Some (one) of the fields are (is) required to be unique. So, a POST with such duplicate data could result in:

    1. 500 - IntegrityError
    2. Make it more like a PUT/PATCH to /<id> and update the existing record
    3. Catch/avoid the error and return some sort of 4XX
    4. Something else I'm not thinking of.

    1 seems out: the request is either bad or I can deal with it. What is the correct way to handle this situation?

    • Steven Fisher
      Steven Fisher over 11 years
      I'd go with 409, "Conflict". But I'm not about to assert that it's the "correct" way. :)
  • igorsantos07
    igorsantos07 over 7 years
    #2 is not correct. POST without an ID should not be used to update a request.