You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The trouble with this technique is that there is only ever a single copy of http_methods and the last call to .update(your_custom_endpoints_dict) will clobber other resource definitions across the entire site.
This works fine for the example in the documentation, because it is defining a new endpoint to be hooked up to a urlconf using cls.as_view('schema'). As long as no other resource similarly overrides the schema http_method with a different mapping, this will work.
But in the following situation, it breaks down a bit:
class CustomEndpointResource(Resource):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.http_methods.update({
'detail': {
'GET': 'detail',
'OPTIONS': 'cors_preflight'
}
})
class InnocentBystanderResource(Resource):
def update(self):
return {"error": "sometimes reached, sometimes not"}
In this example, we want to add the ability for the CustomEndpointResource to respond to OPTIONS requests, for CORS purposes. We expect that when we call self.http_methods.update() we're only updating the http_methods on our own resource. Instead, we're updating our parent class' attribute Resource.http_methods. A race condition ensues where until some request hits CustomEndpointResource, the global http_methods will still contain the default mapping of the PUT HTTP-level method to the update method on InnocentBystanderResource, but once a request comes in for CustomEndpointResource, all further requests to InnocentBystanderResource will fail with an error similar to:
restless.exceptions.MethodNotImplemented: Unsupported method 'PUT' for detail endpoint.
A simple fix for this is to simply instantiate a copy of http_methods inside the __init__ method of the Resource class, but other techniques would work as well. I'm sure this is an intentional API choice, but it contains a nasty gotcha bug for this corner case.
The text was updated successfully, but these errors were encountered:
http_methods
is defined as a class-level attribute on the Resource class.But then the documentation for Custom Endpoints recommends overriding
http_methods
in your resource's__init__
method.The trouble with this technique is that there is only ever a single copy of
http_methods
and the last call to.update(your_custom_endpoints_dict)
will clobber other resource definitions across the entire site.This works fine for the example in the documentation, because it is defining a new endpoint to be hooked up to a urlconf using
cls.as_view('schema')
. As long as no other resource similarly overrides theschema
http_method with a different mapping, this will work.But in the following situation, it breaks down a bit:
In this example, we want to add the ability for the
CustomEndpointResource
to respond toOPTIONS
requests, for CORS purposes. We expect that when we callself.http_methods.update()
we're only updating the http_methods on our own resource. Instead, we're updating our parent class' attributeResource.http_methods
. A race condition ensues where until some request hitsCustomEndpointResource
, the globalhttp_methods
will still contain the default mapping of thePUT
HTTP-level method to theupdate
method onInnocentBystanderResource
, but once a request comes in forCustomEndpointResource
, all further requests toInnocentBystanderResource
will fail with an error similar to:restless.exceptions.MethodNotImplemented: Unsupported method 'PUT' for detail endpoint.
A simple fix for this is to simply instantiate a copy of
http_methods
inside the__init__
method of the Resource class, but other techniques would work as well. I'm sure this is an intentional API choice, but it contains a nasty gotcha bug for this corner case.The text was updated successfully, but these errors were encountered: