Skip to content

feat(openapi): add Scalar docs UI route generation#175

Merged
medz merged 6 commits intomainfrom
feat/openapi-dev-ui
Mar 28, 2026
Merged

feat(openapi): add Scalar docs UI route generation#175
medz merged 6 commits intomainfrom
feat/openapi-dev-ui

Conversation

@medz
Copy link
Copy Markdown
Owner

@medz medz commented Mar 28, 2026

Resolves #172

Summary by CodeRabbit

  • New Features

    • Added an OpenAPI documentation UI (Scalar) that serves an interactive API reference.
    • Configurable docs route, theme, layout, and title; docs route is enabled only when OpenAPI output is a route.
    • Docs are generated and served as an HTTP GET route by default; can be disabled by omitting the UI config.
  • Tests

    • Added tests covering UI generation, customization, route registration, and conditional enabling.

medz and others added 2 commits March 28, 2026 11:32
When `OpenAPIConfig.ui` is set to a `Scalar(...)` instance and the
output is a route, the build generator emits `src/_openapi_docs.dart`
and injects a GET route at the configured path (default `/_docs`) that
serves a Scalar API reference page pointing at the generated
`openapi.json`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 28, 2026

Deploy Preview for dart-spry ready!

Name Link
🔨 Latest commit 1304583
🔍 Latest deploy log https://app.netlify.com/projects/dart-spry/deploys/69c74f914ec7190007f4d51a
😎 Deploy Preview https://deploy-preview-175--dart-spry.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 28, 2026

📝 Walkthrough

Walkthrough

Adds optional Scalar-based OpenAPI UI support to the generator: config accepts ui: Scalar(...); when output is a route and ui is present, generator emits src/_openapi_docs.dart, imports it into the app, and registers a GET route serving an HTML Scalar viewer (configurable route, theme, layout, title).

Changes

Cohort / File(s) Summary
OpenAPI config & example
lib/src/openapi/config.dart, example/openapi/spry.config.dart
Added Scalar extension type and OpenAPIConfig.ui (optional) with route, theme, layout, title; example enables ui: Scalar().
Generator & output files
lib/src/builder/generator.dart, lib/src/.../src/_openapi_docs.dart
Detects hasDocsUi (ui present + output is route); conditionally imports generated docs module, adds GET route mapped to $docs.handler, appends generated src/_openapi_docs.dart file; includes _generateDocsFile and _dartStr helper.
Tests
test/generator_test.dart
New test group asserting docs file generation, app import/route registration, configurable route/theme/layout/title, proper escaping for special chars, and conditional skipping when ui omitted or output is local.
Docs/site content
sites/spry.medz.dev/config.md, sites/spry.medz.dev/guide/openapi.md
Documented ui: Scalar() option, default route /_docs, conditional enabling when output is OpenAPIOutput.route(...), and configurable theme/layout/title; noted assets are CDN-loaded.

Sequence Diagram(s)

sequenceDiagram
    participant Builder as Build Generator
    participant Config as OpenAPI Config
    participant FileGen as File Generator
    participant AppModule as App Module
    participant Client as HTTP Client

    Builder->>Config: Read OpenAPIConfig (document, output, ui)
    Config-->>Builder: Return config + Scalar settings
    Builder->>Builder: Evaluate hasDocsUi (ui != null && output.type == 'route')
    alt UI Enabled
        Builder->>FileGen: _generateDocsFile(openapi) -> create src/_openapi_docs.dart (HTML + Scalar script)
        FileGen-->>Builder: docs file created
        Builder->>AppModule: add import '_openapi_docs.dart' as $docs and register GET ui.route -> $docs.handler
        AppModule-->>Builder: route registered
    else UI Disabled
        Builder->>Builder: Skip docs generation and route injection
    end

    rect rgba(100, 150, 255, 0.5)
    Client->>AppModule: GET /_docs (or configured route)
    AppModule->>FileGen: dispatch to $docs.handler
    FileGen-->>Client: Response handler returns HTML embedding Scalar viewer (data-url, data-theme, data-layout)
    end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰
I stitched a little docs door, neat and spry,
Scalar lights the route where APIs lie.
At /_docs I hop, the spec comes alive,
Themes and titles set — now devs can thrive! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: adding Scalar docs UI route generation to the OpenAPI configuration system.
Linked Issues check ✅ Passed The PR substantially addresses issue #172's requirements: interactive OpenAPI UI mounted at configurable path (default /_docs), Scalar UI support via CDN, opt-in via OpenAPIConfig.ui, requires OpenAPIOutput.route(...), dev-mode generation with proper escaping and path normalization.
Out of Scope Changes check ✅ Passed All changes directly relate to issue #172 objectives: new Scalar extension type, generator logic for docs route, test coverage, and documentation updates are all within scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/openapi-dev-ui

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
test/generator_test.dart (1)

881-1002: Solid test coverage for the OpenAPI UI feature.

The tests cover key configuration scenarios:

  • Title override
  • Theme and layout attributes
  • Custom route path
  • Custom output path
  • Conditional skipping (null ui, local output)

One suggestion for future coverage: consider adding a test for edge cases like special characters in the route path or title (e.g., $ or ') to ensure the escaping in _dartStr and _escape works correctly under all conditions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/generator_test.dart` around lines 881 - 1002, Add a new unit test in
generator_test.dart that verifies OpenAPI UI handles special characters by
exercising the string-escaping helpers: call scan/generate with a BuildConfig
whose OpenAPIConfig.ui Scalar has a title containing characters like $ and ' and
a route containing those characters as well, then assert the produced
src/_openapi_docs.dart and src/app.dart contents include the correctly escaped
title and route (targeting the functions that produce those strings, _dartStr
and _escape, by checking the generated HTML title and data-url and the app route
string). Ensure the test covers both docs present (when output is route) and
that the singleWhere lookups use the same file paths as existing tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/src/builder/generator.dart`:
- Around line 198-214: The generated HTML uses the variable title (from ui.title
/ openapi.document.info.title) which is later embedded into a
triple-single-quoted Dart string (the "'''$html'''" emission) and any occurrence
of ''' in the title will break the generated Dart code; fix by sanitizing the
title before writing HTML—either escape triple-single-quotes (replace "'''" with
"\\'\\'\\'") or emit the title using a safe Dart string literal (e.g., via
jsonEncode or an equivalent string-escaping helper) so that the code produced by
generator.dart (the StringBuffer/html emission and the place that writes
"'''$html'''") cannot be broken by user-provided titles.
- Around line 187-237: The spec URL for the docs file is built unconditionally
as '/${openapi.output.path}' which can produce a double slash when
openapi.output.path already starts with '/', so update _generateDocsFile to
normalize OpenAPIConfig.output.path before building specUrl: trim any leading
slashes from openapi.output.path (or ensure exactly one leading slash) when
constructing specUrl (used in variable specUrl and passed into _dartStr),
leaving _dartStr unchanged; this ensures data-url contains a single leading
slash regardless of how output.path was provided.

---

Nitpick comments:
In `@test/generator_test.dart`:
- Around line 881-1002: Add a new unit test in generator_test.dart that verifies
OpenAPI UI handles special characters by exercising the string-escaping helpers:
call scan/generate with a BuildConfig whose OpenAPIConfig.ui Scalar has a title
containing characters like $ and ' and a route containing those characters as
well, then assert the produced src/_openapi_docs.dart and src/app.dart contents
include the correctly escaped title and route (targeting the functions that
produce those strings, _dartStr and _escape, by checking the generated HTML
title and data-url and the app route string). Ensure the test covers both docs
present (when output is route) and that the singleWhere lookups use the same
file paths as existing tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7718df52-6128-4a5e-95dc-87cc8ff7cd0b

📥 Commits

Reviewing files that changed from the base of the PR and between c18e8a5 and 4e67c45.

📒 Files selected for processing (4)
  • example/openapi/spry.config.dart
  • lib/src/builder/generator.dart
  • lib/src/openapi/config.dart
  • test/generator_test.dart

medz and others added 3 commits March 28, 2026 11:47
A title containing ''' would prematurely terminate the triple-quoted
string literal in the generated _openapi_docs.dart. Extend _dartStr to
replace ''' with \'\'\' before embedding any user-provided value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When OpenAPIOutput.route('/openapi.json') is passed with a leading
slash, prepending '/' produced '//openapi.json'. Strip any leading
slashes from output.path before constructing the spec URL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…alization

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/src/builder/generator.dart`:
- Around line 198-214: The title string is written into the HTML head unescaped
(see the StringBuffer named html and the variable title used in the writeln call
for '<title>$title</title>'); add HTML-escaping of special characters before
interpolation to prevent broken pages or script injection by creating/using a
helper (e.g., escapeHtml or htmlEscape) that replaces &, <, >, " (and optionally
') with entities, and call that helper where title is injected into the
'<title>…</title>' writeln (and any other places where title may be embedded,
such as scriptAttrs) so raw metacharacters are never written directly to the
output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 26cd476a-52dc-4c8e-9089-2d0d457fde2f

📥 Commits

Reviewing files that changed from the base of the PR and between 4e67c45 and 1304583.

📒 Files selected for processing (4)
  • lib/src/builder/generator.dart
  • sites/spry.medz.dev/config.md
  • sites/spry.medz.dev/guide/openapi.md
  • test/generator_test.dart
✅ Files skipped from review due to trivial changes (1)
  • test/generator_test.dart

@medz medz merged commit 5802d00 into main Mar 28, 2026
6 checks passed
@medz medz deleted the feat/openapi-dev-ui branch March 28, 2026 04:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(openapi): built-in UI viewer for dev server (Scalar / Swagger UI)

1 participant