โ ๐ณ¶
โ , ๐ 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
๐, โซ๏ธ ๐ ๐ท. ๐ถ