Skip to content

feat: runtime baseUrl (optional imports) - #3179

Merged
soartec-lab merged 1 commit into
orval-labs:masterfrom
mikan3rd:support_runtime_base_url
Apr 8, 2026
Merged

feat: runtime baseUrl (optional imports)#3179
soartec-lab merged 1 commit into
orval-labs:masterfrom
mikan3rd:support_runtime_base_url

Conversation

@mikan3rd

@mikan3rd mikan3rd commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Approach

Adds baseUrl: { runtime, imports? } so generated clients embed a runtime expression in URL template literals (Issue #3071). This avoids resolving the API host at codegen time and keeps the built-in fetch stack (runtimeValidation, includeHttpResponseReturnType, etc.) without a custom mutator.

Optional imports reuses GeneratorImport so bindings from other modules are emitted into generated files alongside the URL.

Caveats

  • importPath is relative to the generated client file (same idea as mutator paths).
  • MSW host filtering remains mock.baseUrl, separate from output.baseUrl.

Closes #3071

Summary by CodeRabbit

  • New Features

    • Support runtime-configurable API base URLs via JavaScript expressions and emit required imports into generated clients so runtime expressions resolve.
  • Documentation

    • Added “Runtime base URL” guidance to guides and reference docs; clarified how to supply runtime expressions/imports and that mock.baseUrl is separate.
  • Tests

    • Added tests for runtime base URL resolution and import handling.
  • Chore

    • Ensured generated fetch clients remain compatible with existing override.fetch options and prior examples.

@melloware melloware added the fetch Fetch client related issue label Apr 1, 2026
@melloware
melloware requested a review from soartec-lab April 1, 2026 11:54
@soartec-lab

Copy link
Copy Markdown
Member

Thanks! It may take some time, but we will definitely check it.

@coderabbitai

coderabbitai Bot commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a runtime base URL option (baseUrl.runtime) that embeds a JavaScript runtime expression into generated clients' URL template literals; updates types, route generation, tests, client import aggregation, and documentation to support optional runtime imports for that expression.

Changes

Cohort / File(s) Summary
Documentation
docs/content/docs/guides/fetch.mdx, docs/content/docs/guides/set-base-url.mdx, docs/content/docs/reference/configuration/output.mdx
Added "Runtime base URL" docs and examples for baseUrl.runtime and runtime.imports; clarified mock.baseUrl separation and reorganized getBaseUrlFromSpecification/variables/index subsections.
Types
packages/core/src/types.ts
Added BaseUrlRuntime interface (runtime: string, optional imports) and extended OutputOptions / NormalizedOutputOptions.baseUrl to include it; constrained mutual exclusivity with spec-based options.
Route getter logic
packages/core/src/getters/route.ts
Extended getFullRoute to accept BaseUrlRuntime, added isBaseUrlRuntime, runtimeExpressionToUrlPrefix, and exported getBaseUrlRuntimeImports.
Route getter tests
packages/core/src/getters/route.test.ts
Added tests for runtime-expression baseUrls (e.g., process.env.*, import.meta.env.*, env.*) and a getBaseUrlRuntimeImports suite validating import passthrough.
Client generation
packages/orval/src/client.ts
generateOperations now prepends imports from getBaseUrlRuntimeImports(output.baseUrl) to each operation's imports so runtime imports are included in generated clients.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Dev as Developer (generate)
    participant Generator as Orval Generator
    participant Files as Generated Client
    participant Runtime as App Runtime
    participant API as API Server

    Dev->>Generator: run codegen with `baseUrl.runtime` + optional imports
    Generator->>Files: emit client code with template-literal URL prefix ${<runtime expr>} and added imports
    Runtime->>Files: evaluate runtime expression (e.g., process.env / import.meta.env)
    Files->>API: perform fetch to resolved URL
    API-->>Files: response
    Files-->>Runtime: return response (with runtimeValidation / includeHttpResponseReturnType if enabled)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I nibble env vars in the moonlit dew,
A runtime base URL hops into view.
Template strings twine, imports in a row,
One build wanders far—let the fetches go! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: runtime baseUrl (optional imports)' clearly summarizes the main change: adding a runtime baseUrl feature with optional imports configuration.
Linked Issues check ✅ Passed The PR successfully implements the proposed solution from issue #3071 by introducing baseUrl: { runtime, imports? } configuration that embeds runtime expressions into generated URL template literals while preserving built-in fetch options.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing runtime baseUrl support: type definitions, route getter logic, client generation, and comprehensive documentation updates addressing the linked issue requirements.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/core/src/getters/route.ts (1)

26-30: Guard against already-wrapped runtime expressions to fail fast at config time.

The runtimeExpressionToUrlPrefix function (lines 26-30) unconditionally wraps input with ${...}. If a user provides process.env.API_BASE_URL, it correctly produces ${process.env.API_BASE_URL}; however, if they mistakenly pass ${process.env.API_BASE_URL}, the output becomes ${${process.env.API_BASE_URL}}, which is invalid syntax in the generated template literal.

The type guard isBaseUrlRuntime only validates structure and string type—it does not validate content. While JSDoc documentation warns users to pass bare expressions, the code currently relies on compliance without enforcement. Consider adding a guard to detect already-wrapped expressions and throw a clear configuration error.

💡 Proposed fix
 function runtimeExpressionToUrlPrefix(expression: string): string {
   const t = expression.trim();
   if (!t) return '';
+  if (t.startsWith('${') && t.endsWith('}')) {
+    throw new Error(
+      "Invalid output.baseUrl.runtime: provide a JavaScript expression without the `${...}` wrapper.",
+    );
+  }
   return '${' + t + '}';
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/getters/route.ts` around lines 26 - 30, The
runtimeExpressionToUrlPrefix function currently wraps any input in ${...} which
creates invalid nested template syntax when callers already pass a wrapped
expression; update runtimeExpressionToUrlPrefix to detect already-wrapped
expressions (e.g., strings starting with '${' and ending with '}') and throw a
clear configuration error message instead of returning a malformed value;
reference runtimeExpressionToUrlPrefix (and optionally the isBaseUrlRuntime
guard) so you add the check at the start of that function, validate
input.trim(), and throw an Error with a helpful message instructing users to
pass the bare expression (e.g., "runtime expression must not be wrapped with
${...}").
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/core/src/getters/route.ts`:
- Around line 26-30: The runtimeExpressionToUrlPrefix function currently wraps
any input in ${...} which creates invalid nested template syntax when callers
already pass a wrapped expression; update runtimeExpressionToUrlPrefix to detect
already-wrapped expressions (e.g., strings starting with '${' and ending with
'}') and throw a clear configuration error message instead of returning a
malformed value; reference runtimeExpressionToUrlPrefix (and optionally the
isBaseUrlRuntime guard) so you add the check at the start of that function,
validate input.trim(), and throw an Error with a helpful message instructing
users to pass the bare expression (e.g., "runtime expression must not be wrapped
with ${...}").

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1278b371-7955-4446-80bd-e18036fed5cb

📥 Commits

Reviewing files that changed from the base of the PR and between f28371d and b45f830.

📒 Files selected for processing (7)
  • docs/content/docs/guides/fetch.mdx
  • docs/content/docs/guides/set-base-url.mdx
  • docs/content/docs/reference/configuration/output.mdx
  • packages/core/src/getters/route.test.ts
  • packages/core/src/getters/route.ts
  • packages/core/src/types.ts
  • packages/orval/src/client.ts

@soartec-lab soartec-lab left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@mikan3rd
Thank you for the great improvements. I left a few comments, so please check them out.

});
```

### runtime

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please write the details for each parameter, nested within the document structure 👍

### runtime
#### baseUrl
#### imports

@mikan3rd mikan3rd Apr 7, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Headings now follow config keys: ### runtime + #### runtime / #### imports, and ### getBaseUrlFromSpecification + #### variables / #### index. Anchors #runtime and #getbaseurlfromspecification kept.

Comment thread packages/core/src/getters/route.test.ts Outdated
@mikan3rd
mikan3rd requested a review from soartec-lab April 7, 2026 06:42

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/core/src/getters/route.test.ts (1)

148-172: Add one precedence regression case (runtime should win even when servers exists)

Nice coverage for runtime expression patterns. A small extra case would lock in branch precedence and prevent future regressions if getFullRoute condition order changes.

Proposed test case addition
   for (const [path, servers, config, expected] of [
@@
     [
       '/pets',
       undefined,
       { runtime: 'env.API_BASE_URL' },
       '${env.API_BASE_URL}/pets',
     ],
+    [
+      '/pets',
+      [{ url: 'https://from-spec.example.com' }],
+      { runtime: 'process.env.API_BASE_URL' },
+      '${process.env.API_BASE_URL}/pets',
+    ],
     ['/path', undefined, { runtime: '' }, '/path'],
   ] as [string, OpenApiServerObject[] | undefined, BaseUrlRuntime, string][]) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/getters/route.test.ts` around lines 148 - 172, Add a test
case in the existing table-driven tests for getFullRoute that ensures
BaseUrlRuntime.runtime wins even when an OpenApiServerObject[] is provided: add
an entry where path is '/pets', servers is a non-empty array (e.g., [{ url:
'https://api.example.com' }]), config.runtime is a runtime expression like
'process.env.API_BASE_URL', and expected is '${process.env.API_BASE_URL}/pets';
this ensures getFullRoute prioritizes the runtime value over servers.
docs/content/docs/reference/configuration/output.mdx (1)

260-264: Consider adding a brief note about the GeneratorImport shape.

Users unfamiliar with Orval's import configuration may benefit from knowing the basic structure of GeneratorImport. Consider adding a brief inline reference or link to where this type is documented elsewhere (if applicable).

📝 Optional enhancement
 #### imports
 
 **Type:** `GeneratorImport[]`
 
-Optional. When `runtime` references a symbol from another module, list the imports Orval should emit into generated clients. Paths are relative to the generated file, same idea as mutator imports. The `runtime` expression must be valid where the generated code runs (after those imports).
+Optional. When `runtime` references a symbol from another module, list the imports Orval should emit into generated clients. Each entry accepts `name` (the symbol to import) and `importPath` (relative to the generated file, same idea as mutator imports). The `runtime` expression must be valid where the generated code runs (after those imports).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/content/docs/reference/configuration/output.mdx` around lines 260 - 264,
Add a short note describing the shape of GeneratorImport (its key properties and
types) and/or a link to its type definition where the docs live; update the docs
around the "imports" section to include a one-sentence summary of
GeneratorImport (e.g., fields like "path", "names" or "default" and expected
types) and add a "See also" link pointing to the GeneratorImport type
declaration so users can view the full schema; reference the symbol name
GeneratorImport in the text so readers know which type to look up.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@docs/content/docs/reference/configuration/output.mdx`:
- Around line 260-264: Add a short note describing the shape of GeneratorImport
(its key properties and types) and/or a link to its type definition where the
docs live; update the docs around the "imports" section to include a
one-sentence summary of GeneratorImport (e.g., fields like "path", "names" or
"default" and expected types) and add a "See also" link pointing to the
GeneratorImport type declaration so users can view the full schema; reference
the symbol name GeneratorImport in the text so readers know which type to look
up.

In `@packages/core/src/getters/route.test.ts`:
- Around line 148-172: Add a test case in the existing table-driven tests for
getFullRoute that ensures BaseUrlRuntime.runtime wins even when an
OpenApiServerObject[] is provided: add an entry where path is '/pets', servers
is a non-empty array (e.g., [{ url: 'https://api.example.com' }]),
config.runtime is a runtime expression like 'process.env.API_BASE_URL', and
expected is '${process.env.API_BASE_URL}/pets'; this ensures getFullRoute
prioritizes the runtime value over servers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dc651c3c-fc09-4008-b307-bb59558c3551

📥 Commits

Reviewing files that changed from the base of the PR and between 69e9c99 and b7b6f4e.

📒 Files selected for processing (2)
  • docs/content/docs/reference/configuration/output.mdx
  • packages/core/src/getters/route.test.ts

@soartec-lab soartec-lab left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I left a small comment, please check it.

```

### getBaseUrlFromSpecification
### Runtime URL expression {#runtime}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Match the configuration with other properties.

Suggested change
### Runtime URL expression {#runtime}
### baseUrl

@mikan3rd mikan3rd Apr 8, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Using ### runtime instead of ### baseUrl to avoid repeating ## baseUrl. Spec side is ### getBaseUrlFromSpecification for the same reason.


Values for variables used in server URL templates from the OpenAPI `servers` field.

#### index {#index}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
#### index {#index}
#### index

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed {#index} from the #### index heading.

@mikan3rd
mikan3rd requested a review from soartec-lab April 8, 2026 04:01
- BaseUrlRuntime (expression + optional imports), getFullRoute, merge imports in client generator
- Docs (output reference, fetch/set-base-url) and route tests
@mikan3rd
mikan3rd force-pushed the support_runtime_base_url branch from 7801993 to 2024c89 Compare April 8, 2026 04:10

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/core/src/getters/route.ts (1)

83-85: Minor: trailing slash normalization doesn't apply to runtime expressions.

The slash deduplication logic at lines 125-127 checks base.endsWith('/') at codegen time. For runtime expressions, base is literally ${process.env.API_BASE_URL} (ending with }), so this check never triggers. At runtime, if the environment variable ends with / and the route starts with /, the generated URL will have double slashes.

This is an inherent limitation of runtime expressions. Consider documenting that users should ensure their runtime base URL values don't include a trailing slash, or alternatively, apply normalization at runtime:

♻️ Optional: runtime slash normalization
-    if (isBaseUrlRuntime(baseUrl)) {
-      return runtimeExpressionToUrlPrefix(baseUrl.runtime);
-    }
+    if (isBaseUrlRuntime(baseUrl)) {
+      // Trim trailing slash at runtime to avoid double slashes
+      return runtimeExpressionToUrlPrefix(`(${baseUrl.runtime}).replace(/\\/$/, '')`);
+    }

However, this adds complexity and the simpler approach is documenting the expectation. Your call.

Also applies to: 124-129

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

In `@packages/core/src/getters/route.ts` around lines 83 - 85, The runtime base
URL case isn't normalized because the compile-time check uses base.endsWith('/')
on a template expression; update the runtime path by trimming a trailing slash
at runtime when generating the URL (or alternatively add a clear doc comment) —
locate the isBaseUrlRuntime(baseUrl) branch and the runtimeExpressionToUrlPrefix
usage in getRoute/getters/route.ts, and either: 1) change the generated runtime
code to perform a runtime trim (e.g., check the resolved base string for a
trailing '/' and remove it before concatenating with the route), or 2) add a
concise developer/user-facing comment near
isBaseUrlRuntime/runtimeExpressionToUrlPrefix explaining that runtime-provided
base URLs must not include a trailing slash and document this expectation.
Ensure the chosen fix addresses both occurrences where base.endsWith('/') logic
is currently applied.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/core/src/getters/route.ts`:
- Around line 83-85: The runtime base URL case isn't normalized because the
compile-time check uses base.endsWith('/') on a template expression; update the
runtime path by trimming a trailing slash at runtime when generating the URL (or
alternatively add a clear doc comment) — locate the isBaseUrlRuntime(baseUrl)
branch and the runtimeExpressionToUrlPrefix usage in getRoute/getters/route.ts,
and either: 1) change the generated runtime code to perform a runtime trim
(e.g., check the resolved base string for a trailing '/' and remove it before
concatenating with the route), or 2) add a concise developer/user-facing comment
near isBaseUrlRuntime/runtimeExpressionToUrlPrefix explaining that
runtime-provided base URLs must not include a trailing slash and document this
expectation. Ensure the chosen fix addresses both occurrences where
base.endsWith('/') logic is currently applied.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ba8df3ad-af52-4a54-8b11-b03f55adcf2c

📥 Commits

Reviewing files that changed from the base of the PR and between 7801993 and 2024c89.

📒 Files selected for processing (7)
  • docs/content/docs/guides/fetch.mdx
  • docs/content/docs/guides/set-base-url.mdx
  • docs/content/docs/reference/configuration/output.mdx
  • packages/core/src/getters/route.test.ts
  • packages/core/src/getters/route.ts
  • packages/core/src/types.ts
  • packages/orval/src/client.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/orval/src/client.ts
  • docs/content/docs/guides/set-base-url.mdx
  • docs/content/docs/guides/fetch.mdx
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/core/src/getters/route.test.ts
  • docs/content/docs/reference/configuration/output.mdx
  • packages/core/src/types.ts

@soartec-lab soartec-lab left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

sounds good. thanks!

@soartec-lab soartec-lab added this to the 8.6.3 milestone Apr 8, 2026
@soartec-lab soartec-lab added the enhancement New feature or request label Apr 8, 2026
@soartec-lab
soartec-lab merged commit 3b2fc67 into orval-labs:master Apr 8, 2026
1 check passed
@mikan3rd

mikan3rd commented Apr 9, 2026

Copy link
Copy Markdown
Contributor Author

@soartec-lab
Thank you for your review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request fetch Fetch client related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fetch: Support runtime baseUrl (e.g. process.env) without custom mutator

3 participants