Skip to content

Commit 7ae43fb

Browse files
authored
feat: add Scalar API docs alongside Swagger UI (#32)
* feat: add Scalar API docs alongside Swagger UI * match Swagger/Scalar dev banner lines
1 parent cdf3e30 commit 7ae43fb

7 files changed

Lines changed: 42 additions & 5 deletions

File tree

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,11 @@
77
__pycache__/
88
*.pyc
99
*.cover
10+
.env
11+
.envrc
12+
.venv
13+
env/
14+
venv/
15+
ENV/
16+
env.bak/
17+
venv.bak/

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ dependencies = [
2525
"pymysql>=1.1.0",
2626
"langchain>=0.3.9",
2727
"mcp>=1.27.1",
28+
"scalar-fastapi>=1.0.3",
2829
]
2930

3031
[project.optional-dependencies]

scripts/test_cli_dev_studio_smoke.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ def main() -> int:
158158
logs = log_path.read_text(encoding="utf-8", errors="replace")
159159
assert "> Ready!" in logs, logs
160160
assert f"> - API: http://localhost:{api_port}" in logs, logs
161-
assert f"> - Docs: http://localhost:{api_port}/docs" in logs, logs
161+
assert f"> - Docs (Swagger): http://localhost:{api_port}/docs" in logs, logs
162+
assert f"> - Docs (Scalar): http://localhost:{api_port}/scalar-docs" in logs, logs
162163
assert (
163164
"https://smith.langchain.com/studio/?baseUrl="
164165
f"http://127.0.0.1:{api_port}"

src/agentseek_api/cli.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class CliConfig:
6767
class DevServerUrls:
6868
api_url: str
6969
docs_url: str
70+
scalar_docs_url: str
7071
studio_url: str
7172

7273

@@ -324,6 +325,7 @@ def _resolve_dev_urls(*, host: str, port: int, studio_url: str | None) -> DevSer
324325
return DevServerUrls(
325326
api_url=api_url,
326327
docs_url=f"{api_url}/docs",
328+
scalar_docs_url=f"{api_url}/scalar-docs",
327329
studio_url=f"{studio_origin}/studio/?baseUrl={studio_base_url}",
328330
)
329331

@@ -334,7 +336,9 @@ def _render_dev_ready_banner(urls: DevServerUrls) -> str:
334336
">\n"
335337
f"> - API: {urls.api_url}\n"
336338
">\n"
337-
f"> - Docs: {urls.docs_url}\n"
339+
f"> - Docs (Swagger): {urls.docs_url}\n"
340+
">\n"
341+
f"> - Docs (Scalar): {urls.scalar_docs_url}\n"
338342
">\n"
339343
f"> - LangSmith Studio Web UI: {urls.studio_url}\n"
340344
)

src/agentseek_api/main.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
from typing import Any
66

77
from fastapi import Depends, FastAPI, HTTPException, Query, Request, Response
8-
from fastapi.responses import JSONResponse, PlainTextResponse
8+
from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse
9+
from scalar_fastapi import get_scalar_api_reference
910
from starlette.routing import Route
1011

1112
from agentseek_api import __version__
@@ -156,6 +157,14 @@ async def health() -> dict[str, str]:
156157
async def ok() -> dict[str, bool]:
157158
return {"ok": True}
158159

160+
@app.get("/scalar-docs", include_in_schema=False)
161+
async def scalar_docs() -> HTMLResponse:
162+
return get_scalar_api_reference(
163+
openapi_url=app.openapi_url,
164+
title=f"{settings.APP_NAME} - Scalar",
165+
persist_auth=True,
166+
)
167+
159168
@app.get("/info")
160169
async def info() -> dict[str, object]:
161170
return {

tests/unit/test_cli.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ def test_resolve_dev_urls_use_localhost_display_and_loopback_base_url() -> None:
362362

363363
assert urls.api_url == "http://localhost:2024"
364364
assert urls.docs_url == "http://localhost:2024/docs"
365+
assert urls.scalar_docs_url == "http://localhost:2024/scalar-docs"
365366
assert urls.studio_url == "https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024"
366367

367368

@@ -372,6 +373,7 @@ def test_resolve_dev_urls_preserve_explicit_host_and_override_studio_origin() ->
372373

373374
assert urls.api_url == "http://devbox.local:3030"
374375
assert urls.docs_url == "http://devbox.local:3030/docs"
376+
assert urls.scalar_docs_url == "http://devbox.local:3030/scalar-docs"
375377
assert urls.studio_url == "https://smith.example.com/studio/?baseUrl=http://devbox.local:3030"
376378

377379

@@ -413,7 +415,8 @@ def terminate(self) -> None:
413415
assert exit_code == 0
414416
assert "> Ready!" in stdout.getvalue()
415417
assert "- API: http://localhost:2024" in stdout.getvalue()
416-
assert "- Docs: http://localhost:2024/docs" in stdout.getvalue()
418+
assert "- Docs (Swagger): http://localhost:2024/docs" in stdout.getvalue()
419+
assert "- Docs (Scalar): http://localhost:2024/scalar-docs" in stdout.getvalue()
417420
assert "https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024" in stdout.getvalue()
418421
assert opened == ["https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024"]
419422

uv.lock

Lines changed: 12 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)