{# The API console page. `base_template` is a variable rather than a literal: the kit's shell by default, or the app's own `base.html` when `ApiDocsPlugin(base_template=…)` names it, so the docs sit inside the app's chrome without this file knowing anything about it. The layout is the shell's sidebar version, which the shell picks because the `sidebar` block below is not empty. #} {% extends base_template %} {% from "ui/button.html" import button %} {% from "ui/data.html" import card, empty_state, item, item_list, link %} {% from "ui/layout.html" import page_header, section, stack %} {% from "ui/nav.html" import brand %} {% from "ui/sidebar.html" import sidebar %} {% block title %}{{ operation.label if operation else (model.name if model else "API") }}{% endblock %} {% block site_title %}{{ docs_title }}{% endblock %} {# The sidebar keeps `--sidebar-width` as it comes. This page is one of several a host app serves, and a docs route that widened the chrome would make the sidebar jump on every navigation in or out of it. An app that wants a wider one sets the token once for every page it owns, and this page inherits it like the others — which is what the token is for. #} {% block sidebar %} {%- set mark %} {{ brand(docs_title, url_for(request, routes.index), icon_name="braces") }} {# The filter. Swagger has one for the same reason: an app with two hundred routes has a sidebar nobody scrolls, and the tag headings only help someone who already knows the tag. It filters on the server and swaps the list, costing one round trip per pause in typing and buying a list that is genuinely shorter — the client-side version ships all two hundred rows and hides most of them. `delay:250ms` makes it one request per pause rather than one per keystroke. The input sits outside the swapped region, so the text typed and the caret position both survive the swap. A `name` and a real URL, so this is also a GET anybody can bookmark: the page route reads the same `?q=`. #} {%- endset %} {# The way back out. The operation list has taken the sidebar, so without this the docs have no exit — the usual complaint about a `/docs` page bookmarked out of context. #} {%- set exit %} {% if home_url %}{{ button(home_label, variant="ghost", size="sm", href=home_url, icon_name="arrow-left") }}{% endif %} {%- endset %} {% call sidebar(header=mark, footer=exit if home_url else none, label="Operations") %} {% include "apidocs/_nav.html" %} {% endcall %} {% endblock %} {% block content %} {% call stack(gap=6) %} {# The session panel sits above the operation and stays put when one is swapped in. The page is arranged around the question Swagger cannot answer: "who am I right now". #} {% include "apidocs/_session.html" %} {% if operation %} {% include "apidocs/_operation.html" %} {% elif model %} {% include "apidocs/_model.html" %} {% else %} {# The landing state. It carries the detail panel's id so the first click on an operation has something to swap, exactly as the operation partial would. #}
{{ docs.count }} operation{{ "" if docs.count == 1 else "s" }} across {{ docs.groups | length }} group{{ "" if docs.groups | length == 1 else "s" }}{% if docs.models %}, exchanging {{ docs.models | length }} type{{ "" if docs.models | length == 1 else "s" }}{% endif %}, read from the same OpenAPI document {{ link("/openapi.json", "/openapi.json") }} serves. Pick one on the left.
Calls you make here are replayed through this app on the server, carrying your own session. Nothing on this page can read the credential — which is why signing in above is a form your app defines rather than a box to paste a token into.
{% endcall %} {% endcall %} {% else %} {{ empty_state("No operations", "Every route in this app is hidden from the schema, or there are none yet.", "list") }} {% endif %} {# The masthead OpenAPI carries and almost nothing renders: who to ask, what licence it is under, what the terms are, where the prose lives. Somebody wrote each of these into the document meaning it to be read, and dropping them is how a generated reference ends up less informative than the file it came from. #} {%- set masthead = docs.contact or docs.license_name or docs.terms_url or docs.external_url -%} {% if masthead %} {% call card("About this API") %} {% call item_list() %} {% for label, value in docs.contact %} {{ item(label, link(value, ("mailto:" ~ value) if label == "email" else value) if label != "name" else value, clamp=false) }} {% endfor %} {% if docs.license_name %} {{ item("licence", link(docs.license_name, docs.license_url) if docs.license_url else docs.license_name, clamp=false) }} {% endif %} {% if docs.terms_url %} {{ item("terms of service", link(docs.terms_url, docs.terms_url), clamp=false) }} {% endif %} {% if docs.external_url %} {{ item("more", link(docs.external_label, docs.external_url), clamp=false) }} {% endif %} {% endcall %} {% endcall %} {% endif %} {# The tags, with the prose the document wrote for each. A `tags=` list on `FastAPI()` is an information architecture, and a description on one of its entries is the paragraph explaining what that group of endpoints is for — which the sidebar has no room for, and which is the first thing a newcomer to a large API needs. It renders only when somebody wrote one: a list of bare tag names would repeat the sidebar and say nothing. #} {%- set described = docs.groups | selectattr("description") | list -%} {% if described %} {% call card("Groups") %} {% call item_list() %} {% for group in described %} {%- set body %} {{ group.description }} {%- if group.external_url %} — {{ link(group.external_label, group.external_url) }}{% endif -%} {%- endset %} {{ item(group.name, body, clamp=false) }} {% endfor %} {% endcall %} {% endcall %} {% endif %} {% if docs.servers %} {# Shown, not selected. Swagger's server dropdown chooses where its `fetch()` goes; this console replays in-process against the app answering right now, so a dropdown here would change nothing. The list is still worth printing: it is where a real client points. #} {% call card("Servers", "Where a client sends. Try it always goes to this app.") %} {% call item_list() %} {% for server in docs.servers %} {{ item(server.url, server.description or none, clamp=false) }} {% endfor %} {% endcall %} {% endcall %} {% endif %} {% if docs.schemes %} {% call card("Security schemes", "What the document says. Not always the whole story.") %} {% call stack(gap=3) %} {% call item_list() %} {% for scheme in docs.schemes %} {{ item(scheme.name, scheme.type ~ (" · " ~ scheme.detail if scheme.detail else "") ~ (" — " ~ scheme.description if scheme.description else ""), clamp=false) }} {% endfor %} {% endcall %}OpenAPI can only describe an API key, an HTTP scheme, OAuth2 or OpenID Connect. A session cookie issued by your own login is none of those, so it will not appear here even when it is the thing that actually authenticates every call.
{% endcall %} {% endcall %} {% endif %} {% if docs.models %} {# The types, on the landing page as well as in the sidebar. The sidebar is for someone who knows the name; this is for someone finding out that the section exists. #} {% call section("Schemas", "The types this API exchanges — what every generated client is built from.") %}