Skip to content

feat(minibf): add optional base_path configuration#872

Open
adrian1-dot wants to merge 2 commits intotxpipe:mainfrom
adrian1-dot:feat/add-api-v0-base-path
Open

feat(minibf): add optional base_path configuration#872
adrian1-dot wants to merge 2 commits intotxpipe:mainfrom
adrian1-dot:feat/add-api-v0-base-path

Conversation

@adrian1-dot
Copy link

@adrian1-dot adrian1-dot commented Feb 6, 2026

Add optional base_path configuration for Blockfrost API spec compliance

Problem

The Blockfrost OpenAPI specification defines all API endpoints under the /api/v0 base path (see servers section in the official spec). However, Dolos minibf currently serves endpoints directly at the root level (e.g., /network, /blocks/latest), which breaks compatibility with tools and libraries that expect canonical Blockfrost endpoint paths.

This incompatibility causes integration issues with:

  • blockfrost-haskell: Client library with hardcoded /api/v0 base path
  • Other Blockfrost-compatible tooling may also expect standard endpoint structure

Solution

Add an optional base_path configuration field to MinibfConfig that allows nesting all routes under a custom prefix.

Configuration example:

[serve.minibf]
listen_address = "[::]:3000"
base_path = "/api/v0"  # Optional - omit for root-level routes

When configured:

  • All routes become accessible at {base_path}/{endpoint} (e.g., /api/v0/network)
  • Original root-level routes are no longer accessible

Changes

  1. crates/core/src/config.rs: Added base_path: Option<String> field to MinibfConfig
  2. crates/minibf/src/lib.rs: Modified build_router() to conditionally nest all routes when base_path is set (~7 lines)
  3. crates/minibf/README.md: Added documentation for the new configuration option
  4. docs/content/apis/minibf.mdx: Updated API documentation
  5. src/bin/dolos/init.rs: Added base_path to default configuration initialization

Implementation Details

The implementation uses Axum's Router::nest() to wrap the entire route tree under the custom base path when configured:

if let Some(base_path) = &cfg.base_path {
    Router::new().nest(base_path, app).layer(NormalizePathLayer::trim_trailing_slash())
} else {
    app.layer(NormalizePathLayer::trim_trailing_slash())
}

This approach minimizes code changes while providing complete Blockfrost spec compliance.

Backwards Compatibility

  • Fully backwards compatible - when base_path is not configured, all routes remain at root level exactly as before.

Testing

  • All 110 existing tests pass (cargo test --workspace --all-features)
  • No clippy warnings (cargo clippy --workspace --all-features)
  • Successfully tested with local atlas server using /api/v0 base path
  • Verified endpoints accessible at /api/v0/* with base_path configured
  • Verified endpoints at root level when base_path is omitted

Impact

This change enables Dolos minibf to serve as a drop-in replacement for Blockfrost API in tools requiring canonical endpoint paths, significantly improving ecosystem compatibility while maintaining flexibility for users who prefer root-level routes.

Summary by CodeRabbit

  • New Features

    • Added optional base_path configuration to serve all API endpoints under a custom path prefix (e.g., /api/v0); when omitted, endpoints remain at root. Health and metrics endpoints follow the same prefix.
  • Documentation

    • Updated guides and examples to explain base_path usage, defaults, and route namespacing with sample configuration.

Allows nesting all routes under a custom prefix (e.g., /api/v0) for
Blockfrost OpenAPI spec compliance. Backward compatible when unset.
@coderabbitai
Copy link

coderabbitai bot commented Feb 6, 2026

📝 Walkthrough

Walkthrough

A new optional base_path field was added to MinibfConfig to allow API routes to be conditionally nested under a configurable path (e.g., /api/v0). Router construction now nests routes when base_path is set; docs and initialization were updated accordingly.

Changes

Cohort / File(s) Summary
Configuration Structure
crates/core/src/config.rs
Added pub base_path: Option<String> to MinibfConfig with documentation describing route prefixing behavior.
Routing Implementation
crates/minibf/src/lib.rs
Router build now conditionally nests the app under base_path when cfg.base_path is Some, and applies NormalizePathLayer::trim_trailing_slash() within the nested context; previous behavior preserved when None.
Configuration Initialization
src/bin/dolos/init.rs
MinibfConfig literal updated to include base_path: None as the default.
Documentation
crates/minibf/README.md, docs/content/apis/minibf.mdx
Added Blockfrost spec compliance guidance, examples showing route namespacing with base_path, and added base_path entry to configuration docs and TOML example.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A path so fine, now configurable and base,
Routes nest beneath with graceful, elegant grace,
From root or /api/v0, the choice is yours to make,
Blockfrost doors open with each small hop we take,
I twitch my nose and celebrate this tiny change!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding an optional base_path configuration to minibf for API routing.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

Copy link

@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

🤖 Fix all issues with AI agents
In `@crates/core/src/config.rs`:
- Around line 572-575: Update the doc comment for the `base_path:
Option<String>` field in crates/core/src/config.rs to reflect the actual
behavior in `build_router()` (lib.rs): when `base_path` is set, all
routes—including `/health` and `/metrics`—are nested under that base path;
remove or correct the line that says "/health and /metrics remain at root" so
the comment matches the implementation (or, if you prefer the other approach,
modify `build_router()` to exclude `/health` and `/metrics` from nesting under
`base_path`).

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link

@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

🤖 Fix all issues with AI agents
In `@crates/minibf/src/lib.rs`:
- Around line 442-446: The config validation for cfg.base_path is too narrow and
must also reject values missing a leading '/' (and optionally containing
wildcards) to avoid Axum's opaque panic when calling
Router::new().nest(base_path, app); update the check around cfg.base_path in
lib.rs to: ensure base_path is not empty, starts with '/', is not just "/" (as
already done), and does not contain '*' (or other invalid characters you choose
to forbid); if validation fails, panic or return a clear error message
referencing cfg.base_path so callers see a helpful configuration error before
reaching Router::nest (which is where NormalizePathLayer::trim_trailing_slash()
is applied).

Comment on lines +442 to +446
if let Some(base_path) = &cfg.base_path {
if base_path.is_empty() || base_path == "/" {
panic!("base_path must not be empty or \"/\"");
}
Router::new().nest(base_path, app).layer(NormalizePathLayer::trim_trailing_slash())
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Validation doesn't catch a missing leading /, which will cause an opaque panic from Axum.

Axum's Router::nest() requires the path to start with "/" and will panic with its own less-descriptive message if it doesn't. Consider broadening the validation to also reject paths without a leading slash (and optionally paths containing wildcards *), so users get a clear configuration error.

Suggested fix
     if let Some(base_path) = &cfg.base_path {
-        if base_path.is_empty() || base_path == "/" {
-            panic!("base_path must not be empty or \"/\"");
+        if base_path.is_empty() || base_path == "/" || !base_path.starts_with('/') || base_path.contains('*') {
+            panic!(
+                "base_path must start with '/', must not be just '/', and must not contain wildcards; got: \"{base_path}\""
+            );
         }
🤖 Prompt for AI Agents
In `@crates/minibf/src/lib.rs` around lines 442 - 446, The config validation for
cfg.base_path is too narrow and must also reject values missing a leading '/'
(and optionally containing wildcards) to avoid Axum's opaque panic when calling
Router::new().nest(base_path, app); update the check around cfg.base_path in
lib.rs to: ensure base_path is not empty, starts with '/', is not just "/" (as
already done), and does not contain '*' (or other invalid characters you choose
to forbid); if validation fails, panic or return a clear error message
referencing cfg.base_path so callers see a helpful configuration error before
reaching Router::nest (which is where NormalizePathLayer::trim_trailing_slash()
is applied).

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.

1 participant