In order to interact with slack, a server needs to be able to validate requests based on some cryptographic hashing. If this check returns false, the server should respond with a 400. It seems sensible to do this as a mixin:
class SlackValidationMixin:
def dispatch(self, request, *args, **kwargs):
if validate_slack_request(request):
return super().dispatch(request, *args, **kwargs)
else:
return Response(status=status.HTTP_400_BAD_REQUEST)
This gives the error "accepted_renderer not set on Response" Based on a SO question, I added the following:
class SlackValidationMixin:
def dispatch(self, request, *args, **kwargs):
if validate_slack_request(request):
return super().dispatch(request, *args, **kwargs)
else:
response = Response(status=status.HTTP_400_BAD_REQUEST)
response.accepted_renderer = JSONRenderer
response.accepted_media_type = "application/json"
response.renderer_context = {}
return response
But this gives the error: AttributeError: 'NoneType' object has no attribute 'get_indent'
Why does it need an accepted_renderer, given that it is only responding with an HTTP status code, with no additional data? What is the easiest way of getting around this?
Following suggestion in answer to make EmptyResponse object inheriting from Response:
Traceback (most recent call last):
File "path/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "path/lib/python3.8/site-packages/django/utils/deprecation.py", line 96, in __call__
response = self.process_response(request, response)
File "path/lib/python3.8/site-packages/django/middleware/common.py", line 106, in process_response
if response.status_code == 404:
AttributeError: 'dict' object has no attribute 'status_code'
At first the solution: your second approach is fine, you only need to instantiate the
JSONResponseclass (DRF does this in theget_renderersmethod ofviews.APIView):Background:
WSGIHandler(inherited fromBasehandler) callsresponse.render()to render the responseResponse(inherited fromSimpleTemplateResponse) object has arendermethod that gets the rendered content via therendered_contentproperty (which calls therendermethod of the renderer with the passed data, media type and context)DEFAULT_RENDERER_CLASSES/APIView.renderer_classessetting and theAceeptheader passed by client; the selected renderer is set in theHttpRequestobject asaccepted_rendererand the media type asrequest.accepted_media_typeattributesResponseobject also needs therenderer_contextattribute; for example,views.APIViewsets the current view, request, and arguments asrenderer_contextdictNow it should be clear why you need the attributes with
Responseobject -- to get the renderer, media type and to pass any extra context that might be needed by the selected renderer.You've added an answer, where you're setting the above mentioned attributes and then from the renderer returning an empty dict as response. If you want to follow that route, a much easier and cleaner option would be to create a subclass of
Responseand return an empty dict from therendermethod e.g.:Now only returning the
EmptyResponseobject would do, no need to add the renderer related attributes:Now, unless you're adding some custom content, the deferred rendering is not needed; you can directly return
HttpResponseobject:And if you want, you can pass the
content(as bytes) while initializingHttpResponse. But if for some reason, you need lazy rendering, you need to useResponse.render.