Micheal J. Roberts
Micheal J. Roberts

Reputation: 4170

How to correctly set Allow header for a HTTP_405_METHOD_NOT_ALLOWED status code in Django REST framework

I'm currently looking to disable certain methods for an API endpoint - as added security. I'm using the status code that DRF suggests to use, that is for my case, "HTTP_405_METHOD_NOT_ALLOWED" - however, it looks to me that although this is working, the headers still say that the method is in Allow. See screenshot below:

HTTP_405_METHOD_NOT_ALLOWED Django Rest Framework example

As you can see, I am performing a GET request - but the Allow header is saying it's fine - even tho the status code is being applied correctly.

Stripped back example code:

class TokenValidateView(APIView):
    def get(self, request, format=None):
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED, headers=?)

I believe I would need to set something in the headers dictionary (I've added ? where I'm not quite sure what needs to be done) as one of the arguments in the Response() function, but I'm not sure if this is a bug in DRF itself? Surely when that status code is passed it should be set in the headers accordingly?

N.B. I've also tried adding headers = { 'Allow': 'POST' } to the Response() argument, but that doesn't seem to work...

Upvotes: 3

Views: 1477

Answers (3)

Sam
Sam

Reputation: 845

If you don't need the method just don't implement it on view which is subclassing ApiView. It will automatically send the method not allowed response.

Upvotes: 0

JPG
JPG

Reputation: 88539

Since you are using the APIView class, it will allow all the methods which are defined in your view class. The DRF response allowed the HTTP GET method because you'd defined in on your view.


The below view class will allow HTTP GET,HTTP POST,HTTP PATCH,HTTP PUT and HTTP DELETE

class TokenValidateView(APIView):
    def get(self, request, format=None):
        # something
        return Response("this is HTTP GET")

    def post(self, request, format=None):
        return Response("this is HTTP POST")

    def patch(self, request, format=None):
        return Response("this is HTTP PATCH")

    def put(self, request, format=None):
        return Response("this is HTTP PUT")

    def delete(self, request, format=None):
        return Response("this is HTTP DELETE")

As I said above, the response class checks the http methods inside the view class, not their responses.

So, If you want to remove the HTTP GET method from your Allowed Methods, just remove the get() method from the view class

class TokenValidateView(APIView):
    # remove the "get()" method
    def get(self, request, format=None):
        # something
        return Response("this is HTTP GET")

    def post(self, request, format=None):
        return Response("this is HTTP POST")

    def patch(self, request, format=None):
        return Response("this is HTTP PATCH")

    def put(self, request, format=None):
        return Response("this is HTTP PUT")

    def delete(self, request, format=None):
        return Response("this is HTTP DELETE")

Upvotes: 1

zeynel
zeynel

Reputation: 953

When you override the get method of the view,GET is automatically added to the Allow header by django-rest-framework, no matter what Response you return. You can simply remove get method if you want it to return 405 Not Allowed.

If for a reason, you want to keep get method and do not include GET in to the Allow header, you can override allowed_methods property in your view:

@property
def allowed_methods(self):
    allowed_methods = super().allowed_methods
    allowed_methods.remove('GET')
    return allowed_methods

Upvotes: 0

Related Questions