{# The shapes this page repeats: an operation's method, its identity line, its entry in the navigation, and one parameter's input. Macros rather than includes: two of them run once per operation, and an API with two hundred routes renders the navigation two hundred times per page load — the case `{% include %}` in a loop is wrong for. #} {% from "ui/attrs.html" import attrs %} {% from "ui/data.html" import badge, code_block, link %} {% from "ui/form.html" import select_field, text_field %} {% from "ui/icon.html" import icon %} {% from "ui/layout.html" import stack %} {% from "ui/table.html" import cell, table %} {% from "ui/tabs.html" import tab_panel, tabs %} {# Closed lookup, never interpolation. `badge(variant=method|lower)` would emit `data-variant="get"`, which the stylesheet has no rule for, and the badge would lose its colour with nothing to say why. The pairing is the one every API tool has settled on and is worth keeping: green creates, red destroys. HEAD and OPTIONS take the neutral variant, because nobody scans a list for them. #} {% set METHOD_VARIANT = { "GET": "info", "POST": "success", "PUT": "warning", "PATCH": "warning", "DELETE": "destructive", "HEAD": "secondary", "OPTIONS": "secondary", } %} {# method(name) — the coloured verb, wherever an operation is named. #} {% macro method(name) -%} {{ badge(name, METHOD_VARIANT.get(name, "secondary")) }} {%- endmacro %} {# op_line(operation) — verb plus path, the way an API is read aloud. The path is a `kbd` because it is a literal: a reader has to be able to tell `{task_id}` from prose without counting braces. #} {% macro op_line(operation) -%}
{{ operation.path }}
{% if operation.deprecated %}{{ badge("deprecated", "outline") }}{% endif %}
{#
The padlock. An operation the document declares `security` on needs an
authenticated client, and every API browser marks it, because the
alternative is finding out from a 401. The scheme names ride in the
tooltip rather than on screen: on a list where nearly everything is
secured, the same three words after every path is noise.
#}
{% if operation.security %}
{{ icon("lock", 14) }}{{ operation.security | join(", ") }}
{% endif %}
{{ param.name }}
{%- if param.required %} *{% endif %}
{% endcall %}
{{ cell(param.location, tone="muted") }}
{% call cell() %}
{{ param.type_detail }}
{% endcall %}
{% call cell() %}
{{ param.description }}
{%- if param.choices %}
{{ param.choices | join(" | ") }}
{% endif %}
{% endcall %}
{{ row.name }}
{%- if row.required %} *{% endif %}
{% endcall %}
{% call cell() %}
{%- set target = docs.by_name.get(row.ref) if row.ref else none -%}
{% if target %}
{{ link(target.name, url_for(request, routes.model, model_slug=target.slug)) }}
{%- if row.qualifiers %}
{{ row.qualifiers }}
{% endif %}
{% else %}
{{ row.detail }}
{% endif %}
{%- if row.default %}
· default {{ row.default }}
{% endif %}
{% endcall %}
{% call cell() %}
{{ row.description }}
{%- if row.choices %}
{{ row.choices | join(" | ") }}
{% endif %}
{% endcall %}
{{- shape.label -}} {%- set target = docs.by_name.get(shape.model) if shape.model else none -%} {%- if target %} — {{ link("the " ~ target.name ~ " schema", url_for(request, routes.model, model_slug=target.slug)) }}{% endif -%}
{% if shape.has_rows %} {{ field_table(request, routes, docs, shape.fields) }} {% elif not shape.model %} {{ code_block(shape.source, label="Schema for " ~ shape.label, wrap=true) }} {% endif %} {% endcall %} {%- endmacro %} {# payload(request, routes, docs, id, example, shape, example_label) Example and Schema side by side as tabs, wherever a body is described. Tabs rather than two stacked blocks, because a documented 200 with a 15-line example and a 20-row schema is 35 lines of a page whose subject is the endpoint, and only one of the two is read at a time. `id` has to be unique on the page — the tab's `aria-controls` finds its panel by it — so callers prefix it with the status or the word "body". #} {% macro payload(request, routes, docs, id, example, shape, example_label="Example", extra=()) -%} {# Built by concatenation rather than `{% do items.append(…) %}`: the `do` extension is not on this Environment, and turning it on for one macro would be a kit-wide Jinja change made from inside a plugin. `extra` is the document's other named examples — `openapi_examples=` in FastAPI. Swagger puts them in a dropdown; here each is a tab, the same thing without a control that has to be opened to find out what is behind it. They are shown, not loaded into the box: the box is prefilled with the first one, and copying from a tab is one gesture against a route that would have to exist to swap a textarea's value. #} {# A `namespace` and a loop, because Jinja has neither list comprehensions nor `list.append` without the `do` extension. Reassigning a namespace attribute is the one form of accumulation the language does have. #} {%- set ns = namespace(items=[{"id": id ~ "-example", "label": example_label}] if example else []) -%} {%- for label, value in extra -%} {%- set ns.items = ns.items + [{"id": id ~ "-x" ~ loop.index0, "label": label}] -%} {%- endfor -%} {%- set items = ns.items + ([{"id": id ~ "-schema", "label": "Schema"}] if shape else []) -%} {% if items | length > 1 %} {% call tabs(items, label="Body view") %} {% if example %} {% call tab_panel(id ~ "-example") %} {{ code_block(example, label=example_label) }} {% endcall %} {% endif %} {% for label, value in extra %} {% call tab_panel(id ~ "-x" ~ loop.index0) %} {{ code_block(value, label=label) }} {% endcall %} {% endfor %} {% if shape %} {% call tab_panel(id ~ "-schema") %} {{ shape_view(request, routes, docs, shape) }} {% endcall %} {% endif %} {% endcall %} {% elif example %} {% call stack(gap=2) %} {{ example_label }} {{ code_block(example, label=example_label) }} {% endcall %} {% elif shape %} {{ shape_view(request, routes, docs, shape) }} {% endif %} {%- endmacro %}