1

I take the IP address using client.host from the Request object and send this to another function, where I'm using Pydantic's IPvAnyAddress to validate the IP address.

Here is my code:

from fastapi import APIRouter, Request
from pydantic import IPvAnyAddress


route = APIRouter()


@route.get("/ip-address")
def request_ip_address_deblock_link(request: Request):
    return example_function(request.client.host)

def example_function(ip_address: IPvAnyAddress):
    print(ip_address)

But when I'm using FastAPI's TestClient to test my API routes, the IP-address check fails, as the hostname in the request is testclient.

ValueError: 'testclient' does not appear to be an IPv4 or IPv6 address

Is it possible to change the hostname in FastAPI/Starlette's TestClient?

Chris
  • 18,724
  • 6
  • 46
  • 80
  • As far as I can tell the _clients_ hostname is hardcoded as `testclient` in `starlette.testclient.TestClient`, but you might be able to go through having a custom `portal_factory` that changes the content of `scope` before using the original `portal_factory`? Also note that the TestClient changed from being based on requests to httpx in the last couple of days, so there might be a slight behavior change here (even if there shouldn't be one). – MatsLindh Sep 09 '22 at 11:13
  • @MatsLindh From the source code (cited below), it doesn't seem that `portal_factory` is related to `scope`. Is it? – Chris Sep 09 '22 at 11:26
  • @Chris When the portal gets called, it receives `scope` as one of its parameters. But it seems to only happen after the request has happened: https://github.com/encode/starlette/blob/bc61505faef15b673bf4bf65db4927daa354d6b8/starlette/testclient.py#L328 - I'm not familiar with the portal, but it's user configurable and has access to `scope` at least somewhere in the request cycle, so that would be my best bet. – MatsLindh Sep 09 '22 at 11:57

1 Answers1

0

From Starlette's source code on testclient.py here—that FastAPI actually uses under the hood, see here)—the testclient hostname seems to be fixed/hardcoded.

Hence, you could simply check on server side if request.client.host == 'testclient' inside a Dependency function (as @MatsLindh suggested in the comments section), and next, either override testclient with the local IP address, or raise some exception (if you like).

Alternatively, you could use the HTTPX library, also suggested in the FastAPI documentation. FastAPI/Starlette's TestClient is now built on httpx (see the relevant commit on github).

Chris
  • 18,724
  • 6
  • 46
  • 80
  • Or you could move `get_client_ip_address` out to a dependency with `Depends()` and then override that in the testing context – MatsLindh Sep 09 '22 at 11:58