meta::Type and Its Documentation — What an API Description Is Built From, Without AnnotationsStatus: Accepted
Date: October 6, 2026
Answers: what a small service needs to describe its routes - an OpenAPI
document - from what the program already says, before anything is added to
write more
Related:
ADR-304 D4 (a reflected field answers .name and .of(value));
ADR-323 D1 (meta::Type, a type described as data);
ADR-326 (net::serve, http on it);
ADR-289 D14 (routes);
ADR-251 D2 (documentation is not in the ledger);
Part I 1.x (/// is an item’s documentation), Part II 10.3
What can a description of an HTTP API - its paths, and for each request and response every field with its type, whether it may be absent, and what it means - be built from in Nikaia?
A shape walk reads a field’s name and value (ADR-304 D4); the
compiler checks each unrolled turn with the field’s type, but the program cannot
hold that type as a value. meta::Type describes a type as data
(ADR-323), and /// before a field is its documentation (Part I),
which nothing reads.
| Types | Descriptions | Constraints, examples, wire names | |
|---|---|---|---|
| Java (springdoc) | reflection at run time | @Schema(description = …) |
annotations |
| C# (Swashbuckle) | reflection | /// comments and attributes |
attributes |
| Rust (utoipa, serde) | derive macros | doc comments | attributes |
| Python (FastAPI, Pydantic) | type hints | docstrings, Field(description = …) |
ordinary values: Field(ge = 0) |
| Go (swag) | - | directives in comments | directives in comments, unchecked |
From memory, not checked against a version. What transfers: the type and the documentation the program already has, read at build time; the route’s own facts as options where the route is made. What is not decided here: syntax for anything more (#496).
| Option | Why it lost |
|---|---|
| Annotations first | a general construct of the language - for JSON names, validation and mappings too - decided for one use; it has its own record to come |
Directives inside /// (Go’s swag) |
Part I keeps documentation prose the compiler reads no directive from; a directive nobody checks is a mistake nobody sees |
The type as text ("String?") |
the reason ADR-323 gave meta::Type: text is not checked |
.ty, its type as a meta::Type.Changed by ADR-330 D5: .ty is the field’s type itself; its kind is field.ty::kind, and the walk goes on with schema(field.ty).
Changes ADR-304 D4: .ty and .doc join .name and .of(value).
fn schema[T: Struct](value: T) -> String {
let mut out = ""
for field in T::fields {
out += f"{field.name}: {json_type(field.ty)}\n"
}
return out
}
It is known while the program is built, as .name is: each unrolled turn holds
a constant. A field of a struct type is described as Record of that struct’s
fields, each described the same way, so a nested request is described whole; a
type already being described further up is Named, so a type that holds itself
ends; an enum is Named. Nothing about types exists while the program runs
but the constant.
.doc, its documentation as text.The /// lines before the field, as written; empty where there are none, and
where the build has no source of the package that declares the type - a ledger
carries no documentation (ADR-251 D2). It stays prose: nothing is
read out of it.
Answered by ADR-331: a wire name, an example and a deprecation are attributes.
A route’s summary and tags are options of the call that makes the route, in the
http package. A format - an address, a date - is a type of its own, whose name
says it. What has no place yet - a name on the wire other than the field’s, an
example, a field marked deprecated - waits for
#496.
assert a type’s constructor states, as a minimum or a
pattern in the description: to be checked before it is proposed.meta::Field does not
carry.http package lays the description out and where it serves it.