Two regex parameters between single pair of slashes

Is there a way to capture two different path parameters with two different regexes between the same pair of slashes?

For example, I want to be able to capture URLs like this one:

  • /my/path/prefix/ab0123456789myfile.txt

I thought this would work:

@app.get('/my/path/prefix/<mac_address:[a-f0-9]{12}><filename:.*>')
async def myhandler(request, mac_address, filename):
    return text("hi there!")

But it does not. Is it always required to separate path parameters with slashes in the URL?

You are allowed only one regex per path segment. But, checkout the ext path parameter type. I think it will do what you need…

More specifically, your use case would look like this:

@app.get('/my/path/prefix/<mac_address:ext>')
async def myhandler(request, mac_address, ext):
    return text("hi there!")

Alternatively, if you want to have your regex match

@app.get(r"/<address:[a-f0-9]{12}\..*>")
async def mac_address_matcher(request: Request, address: str):
    address, ext = address.split(".", 1)
    return json({"address": address, "ext": ext})

Or, you could register your own param type:

import re

MAC_ADDRESS_PATTERN = re.compile(r"([a-f0-9]{12})(.*)")


def mac_address(param: str) -> tuple[str, str]:
    if match := MAC_ADDRESS_PATTERN.match(param):
        return match.groups()
    raise ValueError(f"Value {param} is not a valid mac address")


app = Sanic("TestApp")
app.router.register_pattern("mac_address", mac_address, MAC_ADDRESS_PATTERN)

@app.get("/<address:mac_address>")
async def mac_address_handler(request: Request, address: tuple[str, str]):
    mac, filename = address
    return json(
        {
            "mac": mac,
            "filename": filename,
        }
    )
1 Like

Thank you, @ahopkins ! Is there an equivalent to register_pattern on version 20.12 (LTS)?

Nevermind, I just noticed that the router has been re-implemented in version 21, so the regex in the example works fine in 20.12…