Skip to content

โ›… ๐Ÿ—ณ

โš , ๐Ÿ‘† 5๏ธโƒฃ๐Ÿ“† ๐Ÿ’ช โš™๏ธ ๐Ÿ—ณ ๐Ÿ’ฝ ๐Ÿ’– Traefik โš–๏ธ ๐Ÿ‘Œ โฎ๏ธ ๐Ÿ“ณ ๐Ÿ‘ˆ ๐Ÿšฎ โž• โžก ๐Ÿ”ก ๐Ÿ‘ˆ ๐Ÿšซ ๐Ÿ‘€ ๐Ÿ‘† ๐Ÿˆธ.

๐Ÿ‘ซ ๐Ÿ’ผ ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ root_path ๐Ÿ”— ๐Ÿ‘† ๐Ÿˆธ.

root_path ๐Ÿ› ๏ธ ๐Ÿšš ๐Ÿ”ซ ๐Ÿ”ง (๐Ÿ‘ˆ FastAPI ๐Ÿ— ๐Ÿ”›, ๐Ÿ”˜ ๐Ÿ’ƒ).

root_path โš™๏ธ ๐Ÿต ๐Ÿ‘ซ ๐ŸŽฏ ๐Ÿ’ผ.

& โšซ๏ธ โš™๏ธ ๐Ÿ”˜ ๐Ÿ•โ” ๐Ÿ—œ ๐ŸŽง-๐Ÿˆธ.

๐Ÿ—ณ โฎ๏ธ ๐ŸŽž โžก ๐Ÿ”ก

โœ”๏ธ ๐Ÿ—ณ โฎ๏ธ ๐ŸŽž โžก ๐Ÿ”ก, ๐Ÿ‘‰ ๐Ÿ’ผ, โ›“ ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿ’ช ๐Ÿ“ฃ โžก /app ๐Ÿ‘† ๐Ÿ“Ÿ, โœ‹๏ธ โคด๏ธ, ๐Ÿ‘† ๐Ÿšฎ ๐Ÿงฝ ๐Ÿ”› ๐Ÿ” (๐Ÿ—ณ) ๐Ÿ‘ˆ ๐Ÿ”œ ๐Ÿšฎ ๐Ÿ‘† FastAPI ๐Ÿˆธ ๐Ÿ”ฝ โžก ๐Ÿ’– /api/v1.

๐Ÿ‘‰ ๐Ÿ’ผ, โฎ๏ธ โžก /app ๐Ÿ”œ ๐Ÿค™ ๐Ÿฆ /api/v1/app.

โœ‹๏ธ ๐ŸŒ ๐Ÿ‘† ๐Ÿ“Ÿ โœ ๐Ÿค” ๐Ÿ“ค /app.

& ๐Ÿ—ณ ๐Ÿ”œ "โŽ" โžก ๐Ÿ”ก ๐Ÿ”› โœˆ โญ ๐Ÿ“ถ ๐Ÿ“จ Uvicorn, ๐Ÿšง ๐Ÿ‘† ๐Ÿˆธ ๐Ÿค” ๐Ÿ‘ˆ โšซ๏ธ ๐Ÿฆ /app, ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿšซ โœ”๏ธ โ„น ๐ŸŒ ๐Ÿ‘† ๐Ÿ“Ÿ ๐Ÿ”Œ ๐Ÿ”ก /api/v1.

๐Ÿ†™ ๐Ÿ“ฅ, ๐ŸŒ ๐Ÿ”œ ๐Ÿ‘ท ๐Ÿ›Ž.

โœ‹๏ธ โคด๏ธ, ๐Ÿ•โ” ๐Ÿ‘† ๐Ÿ“‚ ๐Ÿ› ๏ธ ๐Ÿฉบ ๐ŸŽš (๐Ÿ•ธ), โšซ๏ธ ๐Ÿ”œ โŒ› ๐Ÿคš ๐Ÿ—„ ๐Ÿ”— /openapi.json, โ†ฉ๏ธ /api/v1/openapi.json.

, ๐Ÿ•ธ (๐Ÿ‘ˆ ๐Ÿƒ ๐Ÿ–ฅ) ๐Ÿ”œ ๐Ÿ”„ ๐Ÿ† /openapi.json & ๐Ÿšซ๐Ÿ”œ ๐Ÿ’ช ๐Ÿคš ๐Ÿ—„ ๐Ÿ”—.

โ†ฉ๏ธ ๐Ÿ‘ฅ โœ”๏ธ ๐Ÿ—ณ โฎ๏ธ โžก ๐Ÿ”ก /api/v1 ๐Ÿ‘† ๐Ÿ“ฑ, ๐Ÿ•ธ ๐Ÿ’ช โ˜• ๐Ÿ—„ ๐Ÿ”— /api/v1/openapi.json.

graph LR

browser("Browser")
proxy["Proxy on http://0.0.0.0:9999/api/v1/app"]
server["Server on http://127.0.0.1:8000/app"]

browser --> proxy
proxy --> server

Tip

๐Ÿ“ข 0.0.0.0 ๐Ÿ›Ž โš™๏ธ โ›“ ๐Ÿ‘ˆ ๐Ÿ“‹ ๐Ÿ‘‚ ๐Ÿ”› ๐ŸŒ ๐Ÿ“ข ๐Ÿ’ช ๐Ÿ‘ˆ ๐ŸŽฐ/๐Ÿ’ฝ.

๐Ÿฉบ ๐ŸŽš ๐Ÿ”œ ๐Ÿ’ช ๐Ÿ—„ ๐Ÿ”— ๐Ÿ“ฃ ๐Ÿ‘ˆ ๐Ÿ‘‰ ๐Ÿ› ๏ธ server ๐Ÿ”Ž /api/v1 (โ›… ๐Ÿ—ณ). ๐Ÿ–ผ:

{
    "openapi": "3.0.2",
    // More stuff here
    "servers": [
        {
            "url": "/api/v1"
        }
    ],
    "paths": {
            // More stuff here
    }
}

๐Ÿ‘‰ ๐Ÿ–ผ, "๐Ÿ—ณ" ๐Ÿ’ช ๐Ÿ•ณ ๐Ÿ’– Traefik. & ๐Ÿ’ฝ ๐Ÿ”œ ๐Ÿ•ณ ๐Ÿ’– Uvicorn, ๐Ÿƒโ€โ™‚ ๐Ÿ‘† FastAPI ๐Ÿˆธ.

๐Ÿšš root_path

๐Ÿ† ๐Ÿ‘‰, ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ ๐Ÿ“‹ โธ ๐ŸŽ› --root-path ๐Ÿ’–:

$ uvicorn main:app --root-path /api/v1

<span style="color: green;">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

๐Ÿšฅ ๐Ÿ‘† โš™๏ธ Hypercorn, โšซ๏ธ โœ”๏ธ ๐ŸŽ› --root-path.

๐Ÿ“ก โ„น

๐Ÿ”ซ ๐Ÿ”ง ๐Ÿ”ฌ root_path ๐Ÿ‘‰ โš™๏ธ ๐Ÿ’ผ.

& --root-path ๐Ÿ“‹ โธ ๐ŸŽ› ๐Ÿšš ๐Ÿ‘ˆ root_path.

โœ… โฎ๏ธ root_path

๐Ÿ‘† ๐Ÿ’ช ๐Ÿคš โฎ๏ธ root_path โš™๏ธ ๐Ÿ‘† ๐Ÿˆธ ๐Ÿ”  ๐Ÿ“จ, โšซ๏ธ ๐Ÿ• scope ๐Ÿ“– (๐Ÿ‘ˆ ๐Ÿ• ๐Ÿ”ซ ๐Ÿ”Œ).

๐Ÿ“ฅ ๐Ÿ‘ฅ โœ… โšซ๏ธ ๐Ÿ“ง ๐ŸŽฆ ๐ŸŽฏ.

from fastapi import FastAPI, Request

app = FastAPI()


@app.get("/app")
def read_main(request: Request):
    return {"message": "Hello World", "root_path": request.scope.get("root_path")}

โคด๏ธ, ๐Ÿšฅ ๐Ÿ‘† โ–ถ๏ธ Uvicorn โฎ๏ธ:

$ uvicorn main:app --root-path /api/v1

<span style="color: green;">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

๐Ÿ“จ ๐Ÿ”œ ๐Ÿ•ณ ๐Ÿ’–:

{
    "message": "Hello World",
    "root_path": "/api/v1"
}

โš’ root_path FastAPI ๐Ÿ“ฑ

๐Ÿ‘, ๐Ÿšฅ ๐Ÿ‘† ๐Ÿšซ โœ”๏ธ ๐ŸŒŒ ๐Ÿšš ๐Ÿ“‹ โธ ๐ŸŽ› ๐Ÿ’– --root-path โš–๏ธ ๐ŸŒ“, ๐Ÿ‘† ๐Ÿ’ช โš’ root_path ๐Ÿ”ข ๐Ÿ•โ” ๐Ÿ— ๐Ÿ‘† FastAPI ๐Ÿ“ฑ:

from fastapi import FastAPI, Request

app = FastAPI(root_path="/api/v1")


@app.get("/app")
def read_main(request: Request):
    return {"message": "Hello World", "root_path": request.scope.get("root_path")}

๐Ÿšถโ€โ™€๏ธ root_path FastAPI ๐Ÿ”œ ๐ŸŒ“ ๐Ÿšถโ€โ™€๏ธ --root-path ๐Ÿ“‹ โธ ๐ŸŽ› Uvicorn โš–๏ธ Hypercorn.

๐Ÿ”ƒ root_path

โœ”๏ธ ๐Ÿคฏ ๐Ÿ‘ˆ ๐Ÿ’ฝ (Uvicorn) ๐Ÿ† ๐Ÿšซ โš™๏ธ ๐Ÿ‘ˆ root_path ๐Ÿ•ณ ๐Ÿ™† ๐ŸŒ˜ ๐Ÿšถโ€โ™€๏ธ โšซ๏ธ ๐Ÿ“ฑ.

โœ‹๏ธ ๐Ÿšฅ ๐Ÿ‘† ๐Ÿšถ โฎ๏ธ ๐Ÿ‘† ๐Ÿ–ฅ http://127.0.0.1:8000/app ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ ๐Ÿ˜ ๐Ÿ“จ:

{
    "message": "Hello World",
    "root_path": "/api/v1"
}

, โšซ๏ธ ๐Ÿ† ๐Ÿšซ โŒ› ๐Ÿ” http://127.0.0.1:8000/api/v1/app.

Uvicorn ๐Ÿ”œ โŒ› ๐Ÿ—ณ ๐Ÿ” Uvicorn http://127.0.0.1:8000/app, & โคด๏ธ โšซ๏ธ ๐Ÿ”œ ๐Ÿ—ณ ๐ŸŽฏ ๐Ÿšฎ โž• /api/v1 ๐Ÿ”ก ๐Ÿ”› ๐Ÿ”.

๐Ÿ”ƒ ๐Ÿ—ณ โฎ๏ธ ๐ŸŽž โžก ๐Ÿ”ก

โœ”๏ธ ๐Ÿคฏ ๐Ÿ‘ˆ ๐Ÿ—ณ โฎ๏ธ ๐ŸŽž โžก ๐Ÿ”ก ๐Ÿ•ด 1๏ธโƒฃ ๐ŸŒŒ ๐Ÿ”— โšซ๏ธ.

๐ŸŽฒ ๐Ÿ“š ๐Ÿ’ผ ๐Ÿ”ข ๐Ÿ”œ ๐Ÿ‘ˆ ๐Ÿ—ณ ๐Ÿšซ โœ”๏ธ ๐Ÿš โžก ๐Ÿ”ก.

๐Ÿ’ผ ๐Ÿ’– ๐Ÿ‘ˆ (๐Ÿต ๐ŸŽž โžก ๐Ÿ”ก), ๐Ÿ—ณ ๐Ÿ”œ ๐Ÿ‘‚ ๐Ÿ”› ๐Ÿ•ณ ๐Ÿ’– https://myawesomeapp.com, & โคด๏ธ ๐Ÿšฅ ๐Ÿ–ฅ ๐Ÿšถ https://myawesomeapp.com/api/v1/app & ๐Ÿ‘† ๐Ÿ’ฝ (โœ… Uvicorn) ๐Ÿ‘‚ ๐Ÿ”› http://127.0.0.1:8000 ๐Ÿ—ณ (๐Ÿต ๐ŸŽž โžก ๐Ÿ”ก) ๐Ÿ”œ ๐Ÿ” Uvicorn ๐ŸŽ โžก: http://127.0.0.1:8000/api/v1/app.

๐Ÿ”ฌ ๐ŸŒ โฎ๏ธ Traefik

๐Ÿ‘† ๐Ÿ’ช ๐Ÿ’ช ๐Ÿƒ ๐Ÿฅผ ๐ŸŒ โฎ๏ธ ๐ŸŽž โžก ๐Ÿ”ก โš™๏ธ Traefik.

โฌ Traefik, โšซ๏ธ ๐Ÿ‘ ๐Ÿ’ฑ, ๐Ÿ‘† ๐Ÿ’ช โš— ๐Ÿ—œ ๐Ÿ“ & ๐Ÿƒ โšซ๏ธ ๐Ÿ”— โšช๏ธโžก๏ธ ๐Ÿ“ถ.

โคด๏ธ โœ ๐Ÿ“ traefik.toml โฎ๏ธ:

[entryPoints]
  [entryPoints.http]
    address = ":9999"

[providers]
  [providers.file]
    filename = "routes.toml"

๐Ÿ‘‰ ๐Ÿ’ฌ Traefik ๐Ÿ‘‚ ๐Ÿ”› โ›ด 9๏ธโƒฃ9๏ธโƒฃ9๏ธโƒฃ9๏ธโƒฃ & โš™๏ธ โž•1๏ธโƒฃ ๐Ÿ“ routes.toml.

Tip

๐Ÿ‘ฅ โš™๏ธ โ›ด 9๏ธโƒฃ9๏ธโƒฃ9๏ธโƒฃ9๏ธโƒฃ โ†ฉ๏ธ ๐Ÿฉ ๐Ÿ‡บ๐Ÿ‡ธ๐Ÿ” โ›ด 8๏ธโƒฃ0๏ธโƒฃ ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿšซ โœ”๏ธ ๐Ÿƒ โšซ๏ธ โฎ๏ธ ๐Ÿ“ก (sudo) ๐Ÿ˜Œ.

๐Ÿ”œ โœ ๐Ÿ‘ˆ ๐ŸŽ ๐Ÿ“ routes.toml:

[http]
  [http.middlewares]

    [http.middlewares.api-stripprefix.stripPrefix]
      prefixes = ["/api/v1"]

  [http.routers]

    [http.routers.app-http]
      entryPoints = ["http"]
      service = "app"
      rule = "PathPrefix(`/api/v1`)"
      middlewares = ["api-stripprefix"]

  [http.services]

    [http.services.app]
      [http.services.app.loadBalancer]
        [[http.services.app.loadBalancer.servers]]
          url = "http://127.0.0.1:8000"

๐Ÿ‘‰ ๐Ÿ“ ๐Ÿ”— Traefik โš™๏ธ โžก ๐Ÿ”ก /api/v1.

& โคด๏ธ โšซ๏ธ ๐Ÿ”œ โŽ ๐Ÿšฎ ๐Ÿ“จ ๐Ÿ‘† Uvicorn ๐Ÿƒโ€โ™‚ ๐Ÿ”› http://127.0.0.1:8000.

๐Ÿ”œ โ–ถ๏ธ Traefik:

$ ./traefik --configFile=traefik.toml

INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml

& ๐Ÿ”œ โ–ถ๏ธ ๐Ÿ‘† ๐Ÿ“ฑ โฎ๏ธ Uvicorn, โš™๏ธ --root-path ๐ŸŽ›:

$ uvicorn main:app --root-path /api/v1

<span style="color: green;">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

โœ… ๐Ÿ“จ

๐Ÿ”œ, ๐Ÿšฅ ๐Ÿ‘† ๐Ÿšถ ๐Ÿ“› โฎ๏ธ โ›ด Uvicorn: http://127.0.0.1:8000/app, ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ ๐Ÿ˜ ๐Ÿ“จ:

{
    "message": "Hello World",
    "root_path": "/api/v1"
}

Tip

๐Ÿ‘€ ๐Ÿ‘ˆ โœ‹๏ธ ๐Ÿ‘† ๐Ÿ” โšซ๏ธ http://127.0.0.1:8000/app โšซ๏ธ ๐ŸŽฆ root_path /api/v1, โœŠ โšช๏ธโžก๏ธ ๐ŸŽ› --root-path.

& ๐Ÿ”œ ๐Ÿ“‚ ๐Ÿ“› โฎ๏ธ โ›ด Traefik, โœ… โžก ๐Ÿ”ก: http://127.0.0.1:9999/api/v1/app.

๐Ÿ‘ฅ ๐Ÿคš ๐ŸŽ ๐Ÿ“จ:

{
    "message": "Hello World",
    "root_path": "/api/v1"
}

โœ‹๏ธ ๐Ÿ‘‰ ๐Ÿ•ฐ ๐Ÿ“› โฎ๏ธ ๐Ÿ”ก โžก ๐Ÿšš ๐Ÿ—ณ: /api/v1.

โ†—๏ธ, ๐Ÿ’ญ ๐Ÿ“ฅ ๐Ÿ‘ˆ ๐Ÿ‘ฑ ๐Ÿ”œ ๐Ÿ” ๐Ÿ“ฑ ๐Ÿ”˜ ๐Ÿ—ณ, โฌ โฎ๏ธ โžก ๐Ÿ”ก /app/v1 "โ˜‘" 1๏ธโƒฃ.

& โฌ ๐Ÿต โžก ๐Ÿ”ก (http://127.0.0.1:8000/app), ๐Ÿšš Uvicorn ๐Ÿ”—, ๐Ÿ”œ ๐ŸŽฏ ๐Ÿ—ณ (Traefik) ๐Ÿ” โšซ๏ธ.

๐Ÿ‘ˆ ๐ŸŽฆ โ” ๐Ÿ—ณ (Traefik) โš™๏ธ โžก ๐Ÿ”ก & โ” ๐Ÿ’ฝ (Uvicorn) โš™๏ธ root_path โšช๏ธโžก๏ธ ๐ŸŽ› --root-path.

โœ… ๐Ÿฉบ ๐ŸŽš

โœ‹๏ธ ๐Ÿ“ฅ ๐ŸŽŠ ๐Ÿ•. ๐Ÿ‘ถ

"๐Ÿ›‚" ๐ŸŒŒ ๐Ÿ” ๐Ÿ“ฑ ๐Ÿ”œ ๐Ÿ”˜ ๐Ÿ—ณ โฎ๏ธ โžก ๐Ÿ”ก ๐Ÿ‘ˆ ๐Ÿ‘ฅ ๐Ÿ”ฌ. , ๐Ÿ‘ฅ ๐Ÿ”œ โŒ›, ๐Ÿšฅ ๐Ÿ‘† ๐Ÿ”„ ๐Ÿฉบ ๐ŸŽš ๐Ÿฆ Uvicorn ๐Ÿ”—, ๐Ÿต โžก ๐Ÿ”ก ๐Ÿ“›, โšซ๏ธ ๐Ÿ† ๐Ÿšซ ๐Ÿ‘ท, โ†ฉ๏ธ โšซ๏ธ โŒ› ๐Ÿ” ๐Ÿ”˜ ๐Ÿ—ณ.

๐Ÿ‘† ๐Ÿ’ช โœ… โšซ๏ธ http://127.0.0.1:8000/docs:

โœ‹๏ธ ๐Ÿšฅ ๐Ÿ‘ฅ ๐Ÿ” ๐Ÿฉบ ๐ŸŽš "๐Ÿ›‚" ๐Ÿ“› โš™๏ธ ๐Ÿ—ณ โฎ๏ธ โ›ด 9999, /api/v1/docs, โšซ๏ธ ๐Ÿ‘ท โ˜‘ โ— ๐Ÿ‘ถ

๐Ÿ‘† ๐Ÿ’ช โœ… โšซ๏ธ http://127.0.0.1:9999/api/v1/docs:

โ–ถ๏ธ๏ธ ๐Ÿ‘ฅ ๐Ÿ’š โšซ๏ธ. ๐Ÿ‘ถ ๐Ÿ‘ถ

๐Ÿ‘‰ โ†ฉ๏ธ FastAPI โš™๏ธ ๐Ÿ‘‰ root_path โœ ๐Ÿ”ข server ๐Ÿ—„ โฎ๏ธ ๐Ÿ“› ๐Ÿšš root_path.

๐ŸŒ– ๐Ÿ’ฝ

Warning

๐Ÿ‘‰ ๐ŸŒ… ๐Ÿง โš™๏ธ ๐Ÿ’ผ. ๐Ÿ’ญ ๐Ÿ†“ ๐Ÿšถ โšซ๏ธ.

๐Ÿ”ข, FastAPI ๐Ÿ”œ โœ server ๐Ÿ—„ ๐Ÿ”— โฎ๏ธ ๐Ÿ“› root_path.

โœ‹๏ธ ๐Ÿ‘† ๐Ÿ’ช ๐Ÿšš ๐ŸŽ ๐ŸŽ› servers, ๐Ÿ–ผ ๐Ÿšฅ ๐Ÿ‘† ๐Ÿ’š ๐ŸŽ ๐Ÿฉบ ๐ŸŽš ๐Ÿ”— โฎ๏ธ ๐Ÿ— & ๐Ÿญ ๐ŸŒ.

๐Ÿšฅ ๐Ÿ‘† ๐Ÿšถโ€โ™€๏ธ ๐Ÿ›ƒ ๐Ÿ“‡ servers & ๐Ÿ“ค root_path (โ†ฉ๏ธ ๐Ÿ‘† ๐Ÿ› ๏ธ ๐Ÿ‘จโ€โคโ€๐Ÿ‘จ โ›… ๐Ÿ—ณ), FastAPI ๐Ÿ”œ ๐Ÿ“ฉ "๐Ÿ’ฝ" โฎ๏ธ ๐Ÿ‘‰ root_path โ–ถ๏ธ ๐Ÿ“‡.

๐Ÿ–ผ:

from fastapi import FastAPI, Request

app = FastAPI(
    servers=[
        {"url": "https://stag.example.com", "description": "Staging environment"},
        {"url": "https://prod.example.com", "description": "Production environment"},
    ],
    root_path="/api/v1",
)


@app.get("/app")
def read_main(request: Request):
    return {"message": "Hello World", "root_path": request.scope.get("root_path")}

๐Ÿ”œ ๐Ÿ— ๐Ÿ—„ ๐Ÿ”— ๐Ÿ’–:

{
    "openapi": "3.0.2",
    // More stuff here
    "servers": [
        {
            "url": "/api/v1"
        },
        {
            "url": "https://stag.example.com",
            "description": "Staging environment"
        },
        {
            "url": "https://prod.example.com",
            "description": "Production environment"
        }
    ],
    "paths": {
            // More stuff here
    }
}

Tip

๐Ÿ‘€ ๐Ÿš˜-๐Ÿ— ๐Ÿ’ฝ โฎ๏ธ url ๐Ÿ’ฒ /api/v1, โœŠ โšช๏ธโžก๏ธ root_path.

๐Ÿฉบ ๐ŸŽš http://127.0.0.1:9999/api/v1/docs โšซ๏ธ ๐Ÿ”œ ๐Ÿ‘€ ๐Ÿ’–:

Tip

๐Ÿฉบ ๐ŸŽš ๐Ÿ”œ ๐Ÿ”— โฎ๏ธ ๐Ÿ’ฝ ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿ–Š.

โŽ ๐Ÿง ๐Ÿ’ฝ โšช๏ธโžก๏ธ root_path

๐Ÿšฅ ๐Ÿ‘† ๐Ÿšซ ๐Ÿ’š FastAPI ๐Ÿ”Œ ๐Ÿง ๐Ÿ’ฝ โš™๏ธ root_path, ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ ๐Ÿ”ข root_path_in_servers=False:

from fastapi import FastAPI, Request

app = FastAPI(
    servers=[
        {"url": "https://stag.example.com", "description": "Staging environment"},
        {"url": "https://prod.example.com", "description": "Production environment"},
    ],
    root_path="/api/v1",
    root_path_in_servers=False,
)


@app.get("/app")
def read_main(request: Request):
    return {"message": "Hello World", "root_path": request.scope.get("root_path")}

& โคด๏ธ โšซ๏ธ ๐Ÿ† ๐Ÿšซ ๐Ÿ”Œ โšซ๏ธ ๐Ÿ—„ ๐Ÿ”—.

๐Ÿ—œ ๐ŸŽง-๐Ÿˆธ

๐Ÿšฅ ๐Ÿ‘† ๐Ÿ’ช ๐Ÿ—ป ๐ŸŽง-๐Ÿˆธ (๐Ÿ”ฌ ๐ŸŽง ๐Ÿˆธ - ๐Ÿ—ป) โช โš™๏ธ ๐Ÿ—ณ โฎ๏ธ root_path, ๐Ÿ‘† ๐Ÿ’ช โšซ๏ธ ๐Ÿ›Ž, ๐Ÿ‘† ๐Ÿ”œ โŒ›.

FastAPI ๐Ÿ”œ ๐Ÿ”˜ โš™๏ธ root_path ๐ŸŽ†, โšซ๏ธ ๐Ÿ”œ ๐Ÿ‘ท. ๐Ÿ‘ถ