Can't change headers with DRF APIClient()

Viewed 702

I use APIClient() for my tests. I use Token auth, so I need to use THIS

If we dive into the source code we'll see next:

# rest_framework/test.py
class APIClient(APIRequestFactory, DjangoClient):
    def __init__(self, enforce_csrf_checks=False, **defaults):
        super().__init__(**defaults)
        self.handler = ForceAuthClientHandler(enforce_csrf_checks)
        self._credentials = {}

    def credentials(self, **kwargs):
        """
        Sets headers that will be used on every outgoing request.
        """
        self._credentials = kwarg

Also I use APIClient() as a pytest fixture in my code:

@pytest.fixture(scope="function")
def _api():
    """API factory for anonymous and auth requests"""

    def __api(token=None, field=None):
        api_client = APIClient()
        headers = {}

        if token:
            headers["HTTP_AUTHORIZATION"] = f"Token {token}"
        if field:
            headers["X-CUSTOM-HEADER"] = field

        api_client.credentials(**headers)

        return api_client
    return __api

But if we create TestMiddleware to look for headers, we see next:

lass TestMiddleware:
    def __init__(self, get_response):
        self._get_response = get_response

    def __call__(self, request):
        header = request.headers.get("X-CUSTOM-HEADER") # None
        header = request.META.get("X-CUSTOM-HEADER") # Works fine!
        ...

        # Response processing
        response = self._get_response(request)

        return response

The question is: Have we any way to have access to the X-CUSTOM-HEADER with APIClient() ? Also if I use Postman it obviously works fine with request.headers.get()

1 Answers

The kwargs passed to the credentials() method ends up feeding directly into the constructor for a WSGIRequest; this means the kwargs it accepts aren't HTTP headers, but WSGI environment variables. And HTTP headers passed as WSGI env vars are always prefixed with HTTP_ — e.g. the Authorization header is configured with HTTP_AUTHORIZATION. Also, underscores are used in place of dashes.

To have your X-Custom-Header header come out the other side in request.headers (not request.META, which is a copy of the WSGI env vars), pass HTTP_X_CUSTOM_HEADER instead of X-CUSTOM-HEADER.

Related