Returning a 409_CONFLICT when a unique=True field exists on model

2,881 views
Skip to first unread message

Rod Afshar

unread,
Dec 1, 2012, 10:11:06 PM12/1/12
to django-res...@googlegroups.com
Currently when I try to use CreateAPIView for a model that has a unique=True field, an IntegrityError is returned when it attempts to save a new object that has a conflict. I don't believe there's anything in place currently to handle unique fields, but please let me know if I'm mistaken.

I'm looking for a way to validate that the value submitted for a field is unique when handling a create request. Currently, I have a field-specific validate method setup to catch it and raise a ValidationError. I think this is likely to be the only error that would require a HTTP status code other than 400.

I'm thinking the view should handle deciding whether to give a 400_BAD_REQUEST or 409_CONFLICT, I'm just not sure what would be best to pass from the serializer so it can respond accordingly. Would it be best to create a new dictionary for conflicts? I guess the most ideal thing would be to add a unique=True check at the serializer field level.

class AccountSerializer(serializers.ModelSerializer):
    def validate_email(self, attrs, source):
        email = attrs.get(source)
        if Account.objects.filter(email=email).exists():
            raise serializers.ValidationError('An account with this email already exists.')

        return attrs

Thanks in advance!

-Rod

Marko Tibold

unread,
Dec 2, 2012, 7:03:35 AM12/2/12
to django-res...@googlegroups.com
Hi Rod,

The behaviour you are describing is implemented in this pull request https://github.com/tomchristie/django-rest-framework/pull/451/files , which is pretty much good to merge.

Yet the web server will with this implementation only return a 400, not a 409 (yet).

Making that possible would involve also changing the UpdateModelMixin and the CreateModelMixin.

So basically it's coming, but not just yet.

Hope that helps somewhat.

Marko

Tom Christie

unread,
Dec 2, 2012, 9:52:51 AM12/2/12
to django-res...@googlegroups.com
I think 400 is probably an acceptable status code for uniqueness validation failures. I believe 409 is typically used to handle versioning conflicts. (eg to manage transactional integrity on certain operations)


Richard Wackerbarth

unread,
Dec 2, 2012, 10:38:16 AM12/2/12
to django-res...@googlegroups.com
Tom,

IMHO, 409 is the appropriate error response. 400 is not.

400 has often been used as a default error code for any of the codes in the 400 sequence. However, technically, it is reserved for SYNTAX errors. A non-unique value is not a syntactic error, but rather a semantic one.

Note that "versioning" is given only as an example of the possible cause of a 409 error.
The proper error message would clarify the 409 code with some additional information such as " Field XXXX must be unique"

Richard

From RFC 2616:
10.4.1 400 Bad Request

The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.

10.4.10 409 Conflict
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.

Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being used and the entity being PUT included changes to a resource which conflict with those made by an earlier (third-party) request, the server might use the 409 response to indicate that it can't complete the request. In this case, the response entity would likely contain a list of the differences between the two versions in a format defined by the response Content-Type.

Tom Christie

unread,
Dec 7, 2012, 6:01:37 PM12/7/12
to django-res...@googlegroups.com
None of the validation errors are technically syntax errors but 400 *is* the most appropriate response code for them.
The spec is poorly worded there.  (Ie if you take the syntax error wording at face value then there's no appropriate response code to use for any incorrect but syntactically well-formed requests)

I don't think using 409 for field uniqueness would be a terrible idea, but I don't think it's necessarily more correct, or more useful.

* What status code should we use if theres a uniqueness field validation error, plus other non-uniqueness field validation errors?
* Using 400 for all validation errors is consistent and obvious behavior (In what case would a client need to treat a uniqueness field validation error any differently to any other field validation error?)

Richard Wackerbarth

unread,
Dec 8, 2012, 9:41:39 AM12/8/12
to django-res...@googlegroups.com
On Dec 7, 2012, at 5:01 PM, Tom Christie <christ...@gmail.com> wrote:

None of the validation errors are technically syntax errors but 400 *is* the most appropriate response code for them.

I disagree. You are claiming something that you cannot substantiate. You admit that using 400 is appropriate, in a technical sense, only when you change the definition of the 400 code.

The spec is poorly worded there.  (Ie if you take the syntax error wording at face value then there's no appropriate response code to use for any incorrect but syntactically well-formed requests)

Untrue. The following applies to syntactically well formed requests that fail validation constraints.

10.4.4 403 Forbidden

The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. 

I don't think using 409 for field uniqueness would be a terrible idea, but I don't think it's necessarily more correct, or more useful.

* What status code should we use if theres a uniqueness field validation error, plus other non-uniqueness field validation errors?

403. A validation error that cannot be cured by altering the content of the database "trumps" one which could potentially be cured.

* Using 400 for all validation errors is consistent and obvious behavior (In what case would a client need to treat a uniqueness field validation error any differently to any other field validation error?)

Giving ANY error message is consistent. But that does not mean that it is either correct, or the most useful response available.

The distinction is only that in one case, the validation fails without consideration of the other data in the database and in the other, it fails because some other entry was previously entered.

The usefulness of distinguishing errors should be left to the consumer. The server should not prejudge.

Richard

Tom Christie

unread,
Dec 8, 2012, 12:03:50 PM12/8/12
to django-res...@googlegroups.com
HTTPbis is a refinement of the original HTTP/1.1 spec, that will replace RFC2616 in due course.
The intent of the 400 status code is updated and clarified there.  (Incidentally 403 is also somewhat clarified)

http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-21#section-7.5.1

I absolutely agree that there are plenty of valid cases where you might choose to return 409 due to some db uniqueness constraint,
but for the general purpose case of input validation for generic views, where the responses may contain both field uniqueness validation errors and other non-uniqueness validation errors in the same response, the more general 400 is appropriate.

Rod Afshar

unread,
Dec 23, 2012, 6:39:28 PM12/23/12
to django-res...@googlegroups.com
Apologies for my long absence on this. Thanks for the info, the ModelField validation that made it in to 2.1.7 is great. Makes sense that in the case of both a uniqueness and non-uniqueness validation error being returned a 400 is the more appropriate status. I'm still considering implementing a 409 of just a uniqueness error. My main motive would be to allow a client to easily handle a 400/409 differently (though, I can't think of a great example offhand).

Thanks again, been loving DRF.

-Rod
Reply all
Reply to author
Forward
0 new messages