Skip to content

Conversation

@Mpdreamz
Copy link
Member

@Mpdreamz Mpdreamz commented Jan 6, 2026

API Explorer: Interactive Schema Documentation

This PR introduces a comprehensive API documentation explorer with support for rendering complex OpenAPI schemas, interactive property navigation, and dedicated type pages.

cursorful-video-1767709036040.mp4

Layout & Integration

Updated layout to integrate with assembler builds - constrained widths matching regular documentation pages.
01-operation-overview

Request & Response Body Rendering

Full support for rendering request and response bodies with:

  • Property names, types, and descriptions
  • Required/optional indicators
  • Expandable nested properties with collapse state
02-request-body

Nested Property Expansion

Expandable tree structure for complex nested types with property counts and expand/collapse toggles:
03-nested-properties

Complex Type Support

Union Types (oneOf/anyOf)

Renders union types with grouped variants, showing X and X[] pairs together:
07-union-types

Recursion Detection

Detects recursive type references (including through arrays and unions) and displays a "Recursive" badge to prevent infinite expansion:
06-recursion-detection

Properties like bool.filter, bool.must, bool.should correctly show the recursive badge when they reference their parent QueryContainer type.

Dedicated Type Pages

Complex types get their own dedicated documentation pages with full property exploration:
05-type-page

Examples

Request and response examples rendered with syntax highlighting:
04-examples

External Documentation Links

Reference documentation links rendered as buttons below descriptions:

  • Elastic docs: "Read the reference documentation" (same-tab navigation)
  • External docs: "External documentation" (new tab)
08-external-docs-button

Property-level docs buttons are shown after property descriptions (skipped if type has dedicated page).

Technical Highlights

  • Shared Razor partials: _PropertyList, _PropertyItem, _UnionOptions, _SchemaType for consistent rendering
  • HTMX integration: Document-level event delegation for SPA navigation
  • Find-in-page support: Uses hidden="until-found" for collapsed sections in supported browsers
  • Configurable collapse modes: Depth-based (SchemaView) vs always-collapsed (OperationView)

Integrates a new `ValidationConstraintsRenderer` to display schema validation constraints in API docs. Updates the relevant views and adds CSS styling for better presentation.
Introduces support for displaying response headers in API explorer views. Updates the view logic and adds corresponding CSS styling for consistent and clear presentation.
Introduces logic and styling to display operation-level and document-level servers, as well as security requirements for operations. Updates corresponding views and CSS for consistent appearance.
- Remove redundant null checks where boolean flags already guarantee non-null
- Add null-forgiving operators where compiler requires them but logic guarantees non-null
- Fix null dereference pattern in OperationView request body handling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
var content = operation.RequestBody.Content?.FirstOrDefault().Value;
var requestContentEntry = operation.RequestBody.Content?.FirstOrDefault();
var requestContentType = requestContentEntry?.Key ?? "application/json";
var requestMediaType = requestContentEntry?.Value;
{
var refId = baseOption.Ref;
if (string.IsNullOrEmpty(refId) && baseOption.Schema is OpenApiSchemaReference schemaRef)
refId = schemaRef.Reference.Id;
{
var refId = primaryOption.Ref;
if (string.IsNullOrEmpty(refId) && schemaToRender is OpenApiSchemaReference schemaRef)
refId = schemaRef.Reference?.Id;
Comment on lines +58 to +80
foreach (var unionSchema in unionSchemas)
{
if (unionSchema == null) continue;
var unionTypeInfo = Model.Analyzer.GetTypeInfo(unionSchema);
var typeName = unionTypeInfo.TypeName;
// Strip [] suffix for array types
var baseName = typeName?.EndsWith("[]") == true ? typeName[..^2] : typeName;
if (!string.IsNullOrEmpty(baseName) && !SchemaHelpers.IsPrimitiveTypeName(baseName) && Model.AncestorTypes.Contains(baseName))
{
isRecursive = true;
break;
}
// Also check if the union option is an array pointing to an ancestor type
if (unionTypeInfo.IsArray && unionSchema.Items != null)
{
var itemTypeInfo = Model.Analyzer.GetTypeInfo(unionSchema.Items);
if (!string.IsNullOrEmpty(itemTypeInfo.TypeName) && !SchemaHelpers.IsPrimitiveTypeName(itemTypeInfo.TypeName) && Model.AncestorTypes.Contains(itemTypeInfo.TypeName))
{
isRecursive = true;
break;
}
}
}
Comment on lines +81 to +89
foreach (var subSchema in allOf)
{
var subProps = GetSchemaProperties(subSchema);
if (subProps is not null)
{
foreach (var prop in subProps)
_ = props.TryAdd(prop.Key, prop.Value);
}
}
Comment on lines +64 to +69
if (!string.IsNullOrEmpty(refId))
{
// Try to get the resolved schema from the document
if (document.Components?.Schemas?.TryGetValue(refId, out var resolvedSchema) == true)
return GetSchemaProperties(resolvedSchema);
}
Comment on lines +363 to +367
if (itemInfo is { IsObject: false, HasLink: false })
{
if (string.IsNullOrEmpty(itemInfo.SchemaRef))
arrayItemType = itemInfo.TypeName;
}
</p>
<h1>
@operation.Summary
@if (operation.Deprecated == true)
{
<dt id="@path.Name"><a href="#@path.Name"><code>@path.Name</code></a></dt>
<dd>@Model.RenderMarkdown(path.Description)</dd>
<div class="path-param @(path.Deprecated == true ? "deprecated" : "")">
…ariable'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
<dt id="[email protected]">
<a href="#[email protected]">
<code>@path.Name</code>
@if (path.Deprecated == true)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants