Files
ComfyUI/app/api_docs.py
Claude ec820735c7 Simplify api docs module and tests
Cleanup pass over the previous commit. No behaviour change except the
cache header noted below.

app/api_docs.py (111 -> 59 lines):

- Cut the rationale comments. The file was ~32% commentary against 2-6%
  in neighbouring app/ modules, and most of it argued decisions that
  belong in the PR rather than the source, including a TODO explaining
  why an SRI hash could not be computed.
- Inline the spec and bundle URLs into the HTML. The __TOKEN__ replace()
  machinery existed only to hoist two string literals, and then needed a
  comment defending its own existence.
- Drop the hand-rolled <style> block for two inline style attributes.
- Drop the os.path.isfile guard. FileResponse already answers a missing
  file with a 404, so the check was a second stat for the same result.

- Serve the spec with Cache-Control: no-cache rather than no-store.
  Both mean "never use a stale copy", but no-store also forbids storing
  it, so every docs page load re-transferred all 230 KB. no-cache lets
  the browser revalidate against the ETag FileResponse already sets; an
  unchanged spec now costs a 304 instead of a full download.

tests-unit/server_test/test_api_docs.py (11 tests -> 6, 144 -> 70 lines):

- Drop the local copy of server.py's /api prefix loop and the two tests
  that depended on it. They exercised the copy, not the real loop, so
  they would have stayed green through a change to the thing they
  claimed to protect. What actually makes prefixing work is that the
  spec URL is relative, which is now asserted directly.
- Drop the static-catch-all test. It asserted aiohttp's own route
  precedence against a synthetic app, and could not fail if the
  registration call moved after the catch-all in server.py.
- Drop the tautological SPEC_PATH assertion, already covered by fetching
  the spec through the route.
- Loosen the fallback assertions, which pinned the exact quoting and
  inline-handler style of the HTML.

Claude-Session: https://claude.ai/code/session_01BvUveU9ofyGrSz3QxYeecB
2026-08-14 23:49:26 +00:00

60 lines
2.1 KiB
Python

"""Serves openapi.yaml and renders it as browsable API docs.
Uses Redoc, not Swagger UI: the local server is unauthenticated by default, so
the viewer must not be able to execute requests.
"""
import os
from aiohttp import web
SPEC_PATH = os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "openapi.yaml"
)
# The spec URL is relative so it resolves from both /api-docs and /api/api-docs.
# The viewer is pinned and loaded from a CDN, so the page needs network access;
# if it fails to load, the fallback below points at the locally served spec.
API_DOCS_HTML = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>ComfyUI API Reference</title>
</head>
<body style="margin: 0">
<redoc spec-url="openapi.yaml"></redoc>
<div id="fallback" style="display: none; margin: 3rem; line-height: 1.6">
The API docs viewer is loaded from a CDN and could not be reached. The
specification itself is served locally: <a href="openapi.yaml">openapi.yaml</a>
</div>
<script
src="https://cdn.jsdelivr.net/npm/redoc@2.5.0/bundles/redoc.standalone.js"
onerror="document.getElementById('fallback').style.display='block'"
></script>
</body>
</html>
"""
def add_api_docs_routes(routes: web.RouteTableDef) -> None:
"""Register /openapi.yaml and /api-docs on the given route table."""
@routes.get("/openapi.yaml")
async def get_openapi_spec(request):
# The spec is edited in place during development, so never let the
# browser hold a stale copy. no-cache still allows a 304 via the ETag
# FileResponse sets, which matters for a ~230 KB file.
return web.FileResponse(SPEC_PATH, headers={
"Content-Type": "application/yaml",
"Cache-Control": "no-cache",
})
@routes.get("/api-docs")
async def get_api_docs(request):
return web.Response(
text=API_DOCS_HTML,
content_type="text/html",
headers={"Cache-Control": "no-cache"},
)