Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

endpoints.ServiceException subclass returning 400 status code instead of 409

In the Cloud Endpoints documentation for exception handling, it is recommended to subclass the endpoints.ServiceException class to provide a custom http_status for 409 Conflict errors. This answer to another question indicates that some of the supported status codes get mapped by Google's infrastructure to other status codes, but 409 isn't one of the mapped status codes.

Using the ConflictException class from the documentation:

import endpoints
import httplib

class ConflictException(endpoints.ServiceException):
    """Conflict exception that is mapped to a 409 response."""
    http_status = httplib.CONFLICT

When I raise the ConflictException:

@endpoints.method(request_message=apimodels.ClientMessage,
                  response_message=apimodels.ClientMessage,
                  name='insert',
                  path='/clients',
                  http_method='POST'
)
def insert(self, request):
    client = models.Client.get_by_id(request.client_code)
    if client:
        raise ConflictException('Entity with the id "%s" exists.' % request.client_code)

    ...

I'm getting a 400 Bad Request as the response:

400 Bad Request

Content-Length:  220
Content-Type:  application/json
Date:  Thu, 27 Feb 2014 16:11:36 GMT
Server:  Development/2.0

{
 "error": {
  "code": 400,
  "errors": [
   {
    "domain": "global",
    "message": "Entity with the id \"FOO\" exists.",
    "reason": "badRequest"
   }
  ],
  "message": "Entity with the id \"FOO\" exists."
 }
}

I'm getting the same 400 response code on both the local dev_appserver and deployed to App Engine (on 1.9.0). Stepping into the App Engine ProtoRPC code, the following line appears to be mapping all remote.ApplicationError types to a 400 status code.

If I update the endpoints.apiserving._ERROR_NAME_MAP dict to add my custom ConflictException class, I'm able to return a 409 successfully:

import endpoints
import httplib
from endpoints.apiserving import _ERROR_NAME_MAP

class ConflictException(endpoints.ServiceException):
    """Conflict exception that is mapped to a 409 response."""
    http_status = httplib.CONFLICT


_ERROR_NAME_MAP[httplib.responses[ConflictException.http_status]] = ConflictException

Is this the correct way to implement endpoints.ServiceException subclasses?

like image 397
Brian Weller Avatar asked Feb 27 '14 16:02

Brian Weller


1 Answers

It seems to be a bug as according to the bug report filed by Chris.

like image 78
user3852065 Avatar answered Nov 04 '22 07:11

user3852065