Fastapi: I cannot add any extra parameters to paths including file-paths

Created on 9 Nov 2020  路  4Comments  路  Source: tiangolo/fastapi

First check

  • [x] I added a very descriptive title to this issue.
  • [x] I used the GitHub search to find a similar issue and didn't find it.
  • [x] I searched the FastAPI documentation, with the integrated search.
  • [x] I already searched in Google "How to X in FastAPI" and didn't find any information.
  • [x] I already read and followed all the tutorial in the docs and didn't find an answer.
  • [x] I already checked if it is not related to FastAPI but to Pydantic.
  • [x] I already checked if it is not related to FastAPI but to Swagger UI.
  • [x] I already checked if it is not related to FastAPI but to ReDoc.
  • [x] After submitting this, I commit to one of:

    • Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.

    • I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.

    • Implement a Pull Request for a confirmed bug.

Example

Here are two test that checks

import pytest
from urllib.parse import quote_plus
from pydantic import constr


@pytest.fixture
def client():
    # https://fastapi.tiangolo.com/tutorial/path-params/#path-convertor
    app = FastAPI()

    @app.get("/files/{file_path:path}").                    #(1)
    def get_file(file_path: str):
        return {"path": file_path}

    @app.get("/files/{file_path:path}/{version}").    #(2)
    def get_file_with_version(  
        file_path:str, version: constr(regex=r"[\d\.]+")
    ):
        return {"path": file_path, "version": version}

    with TestClient(app) as cli:
        yield cli


def test_with_double_slash(client):
    file_path = "/home/johndoe/myfile.txt"

    # Users // as noted in the Tip in https://fastapi.tiangolo.com/tutorial/path-params/#path-convertor
    resp = client.get(f"/files/{file_path}")
    assert resp.status_code == 200, resp.json()
    assert resp.json()["path"] == file_path

    resp = client.get(f"/files/{file_path}/3.5.4")
    assert resp.status_code == 200, resp.json()
    assert resp.json()["path"] == file_path
    assert resp.json()["version"] == "3.5.4"


def test_with_quoted_path(client):
    file_path = "/home/johndoe/myfile.txt"
    quoted_path = quote_plus(file_path)

    print()
    print("Request done with:", f"/file/{quoted_path}")
    print()

    resp = client.get(f"/files/{quoted_path}")
    assert resp.status_code == 200, resp.json()
    assert resp.json()["path"] == file_path

    resp = client.get(f"/files/{quoted_path}/3.5.4")
    assert resp.status_code == 200, resp.json()
    assert resp.json()["path"] == file_path
    assert resp.json()["version"] == "3.5.4"

Description

Dear FastAPI gurus,

I am trying to add a route as files/{file_path}/{version}, where file_path: Path and version: str.
I am aware that the path convertor allows the file path but as soon as I try adding an extra parameter, it is not able to separate both entries.

I also noticed that the order in which the routes are included, produce different result.

  • Run test above
  • Both tests FAIL in the second assert, when the version is added
  • Now, revert the declaration of routes (i.e. #(2) and then #(1)
  • Now the first assert fails since fastapi routes it to #(2) instead of #(1)

Environment

  • OS: [e.g. Linux / Windows / macOS]:
    Linux
  • FastAPI Version:
    0.61.2
  • Python version:
    Python 3.6.12
question

All 4 comments

I also noticed that the order in which the routes are included, produce different result.

You are supposed to notice! Check this: https://fastapi.tiangolo.com/tutorial/path-params/?h=+order+matter#order-matters

I also noticed that the order in which the routes are included, produce different result.

You are supposed to notice! Check this: https://fastapi.tiangolo.com/tutorial/path-params/?h=+order+matter#order-matters

Thx @Kludex I missed that one.

But it still does not explain the issues with the path

I need to investigate. If someone has time, or if you want @pcrespov, you can check https://github.com/encode/starlette/blob/master/starlette/routing.py and search for path:path and try to find out why you have this issue.

Solution until then: if you use a forward slash at the end, like /home/johndoe/myfile.txt/, it works as supposed.
Code that works:

from fastapi import FastAPI
from pydantic import constr

app = FastAPI()

@app.get("/files/{file_path:path}/{version}")
def get_file_with_version(file_path:str, version: constr(regex=r"[\d\.]+")):
    return {"path": file_path, "version": version}

@app.get("/files/{file_path:path}")
def get_file(file_path: str):
    return {"path": file_path}

I need to investigate. If someone has time, or if you want @pcrespov, you can check https://github.com/encode/starlette/blob/master/starlette/routing.py and search for path:path and try to find out why you have this issue.

@Kludex thx again! I will investigate the issue in starlette as well

Was this page helpful?
0 / 5 - 0 ratings