Skip to content

[dart-dio] fix: URI-encode path parameters - #25544

Merged
wing328 merged 4 commits into
OpenAPITools:masterfrom
Inf1mum:fix/dart-dio-path-param-encoding
Nov 4, 2026
Merged

wing328 merged 4 commits into
OpenAPITools:masterfrom
Inf1mum:fix/dart-dio-path-param-encoding

Conversation

@Inf1mum

@Inf1mum Inf1mum commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #25527.

The dart-dio generator built request paths by substituting path parameters through the api/query_param helper — which (for built_value) passes strings through unchanged and (for freezed / json_serializable) interpolates the raw value. A path parameter containing /, spaces, or other reserved characters was therefore sent unencoded and broke the request path (e.g. a scanned QR-code URL as {bin} → 404).

What changed

  • New serialization/<library>/api/path_param.mustache for all three serialization libraries (built_value, freezed, json_serializable) wrapping the existing query_param rendering in Uri.encodeComponent(...) — suggested in the issue and credited to the reporter.
  • api.mustache now substitutes path parameters via api/path_param instead of api/query_param.

Uri.encodeComponent encodes the value as a single path component (including / → %2F), so values containing slashes stay within one segment — exactly the failing scenario from the issue.

Verification

  • New unit test testPathParamsAreUriEncoded generates the petstore client for all three serialization libraries and asserts Uri.encodeComponent( appears in the generated API classes. DartDioClientCodegenTest: 20 tests, 0 failures.
  • Regenerated all 9 dart-dio sample configs; every path substitution now goes through Uri.encodeComponent.
  • dart analyze on the regenerated built_value petstore sample: no issues (one pre-existing unrelated unused_import warning).

PR checklist

  • Read the contribution guidelines.
  • Regenerated the affected samples via ./bin/generate-samples.sh (all dart-dio configs); no files deleted.
  • Pull request is created against the master branch.

Summary by cubic

Fixes #25527. Generated dart-dio clients now URI-encode path parameters, so values containing / or spaces no longer break the request path.

  • Path parameters are substituted via a new api/path_param partial for all three serialization libraries (built_value, freezed, json_serializable), wrapping the value in Uri.encodeComponent on a single line to keep the generated path style unchanged.
  • api.mustache now uses this partial for path parameters instead of the query-param rendering.
  • Adds a unit test covering all three serialization libraries that asserts every path substitution in each generated API class is URI-encoded, and regenerates the affected samples.
  • Pins source_helper to >=1.3.8 <1.4.0 in the freezed variant's pubspec.mustache; version 1.4.0 added extension members that clash with json_serializable 6.x and break the build_runner build script, while 1.3.9+ requires Dart 3.9 (above the variant's advertised >=3.8.0).

Written for commit 594a4aa. Summary will update on new commits.

View guided diff

The query_param helpers pass strings through unchanged (built_value)
or interpolate raw values (freezed, json_serializable), so path
parameters containing '/', spaces or other reserved characters broke
the request path. Substitute path params through a new api/path_param
partial that wraps the value in Uri.encodeComponent for all three
serialization libraries.

Fixes OpenAPITools#25527

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 17 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="modules/openapi-generator/src/test/java/org/openapitools/codegen/dart/dio/DartDioClientCodegenTest.java">

<violation number="1" location="modules/openapi-generator/src/test/java/org/openapitools/codegen/dart/dio/DartDioClientCodegenTest.java:499">
P2: These independent substring assertions do not prove that path parameters are encoded. Assert the complete placeholder replacement expression, or exercise a generated client with a value containing `/` or spaces and verify the resulting request path.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic


Path petApi = output.toPath().resolve("lib/src/api/pet_api.dart");
String content = Files.readString(petApi, StandardCharsets.UTF_8);
Assert.assertTrue(content.contains(".replaceAll("), content);

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.

P2: These independent substring assertions do not prove that path parameters are encoded. Assert the complete placeholder replacement expression, or exercise a generated client with a value containing / or spaces and verify the resulting request path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At modules/openapi-generator/src/test/java/org/openapitools/codegen/dart/dio/DartDioClientCodegenTest.java, line 499:

<comment>These independent substring assertions do not prove that path parameters are encoded. Assert the complete placeholder replacement expression, or exercise a generated client with a value containing `/` or spaces and verify the resulting request path.</comment>

<file context>
@@ -471,6 +471,37 @@ public void testFreezedIgnoresUseOptional() throws IOException {
+
+            Path petApi = output.toPath().resolve("lib/src/api/pet_api.dart");
+            String content = Files.readString(petApi, StandardCharsets.UTF_8);
+            Assert.assertTrue(content.contains(".replaceAll("), content);
+            Assert.assertTrue(content.contains("Uri.encodeComponent("),
+                    "path parameter should be URI-encoded in " + serializationLibrary + ": " + content);
</file context>

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.

Strengthened in 5301a77: testPathParamsAreUriEncoded now iterates every generated *_api.dart file and asserts the count of Uri.encodeComponent( calls equals the count of .replaceAll( path substitutions — so any future path substitution added without encoding fails the test. 20 tests, 0 failures.

source_helper 1.4.0 (published 2026-10-19) added extension members
that clash with json_serializable 6.x's internal copies, breaking
compilation of the build_runner build script ('toStringNonNullable is
defined in multiple extensions'). The json_serializable variant is
unaffected because copy_with_extension_gen's source_gen constraint
holds source_helper below 1.4.0; the freezed variant has no such
guard and floated to 1.4.0.

Verified with Dart 3.9: pub get resolves source_helper 1.3.13,
build_runner builds, dart test passes (190 tests).

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 2 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

- render Uri.encodeComponent on one line so generated paths keep the
  previous single-line style
- assert in testPathParamsAreUriEncoded that the number of
  Uri.encodeComponent calls equals the number of path substitutions in
  every generated api class, not just that one occurrence exists

Addresses review feedback in OpenAPITools#25544.
Inf1mum added a commit to Inf1mum/openapi-generator that referenced this pull request Nov 3, 2026
- render Uri.encodeComponent on one line so generated paths keep the
  previous single-line style
- assert in testPathParamsAreUriEncoded that the number of
  Uri.encodeComponent calls equals the number of path substitutions in
  every generated api class, not just that one occurrence exists

Addresses review feedback in OpenAPITools#25544.
source_helper 1.3.9+ requires Dart 3.9, but the freezed variant
advertises sdk >=3.8.0 - 1.3.8 (source_gen >=3.1.0 <5.0.0, Dart
^3.7.0) keeps 3.8 users able to resolve while 3.9+ users still get
1.3.13.

Addresses review feedback in OpenAPITools#25544.
Inf1mum added a commit to Inf1mum/openapi-generator that referenced this pull request Nov 3, 2026
source_helper 1.3.9+ requires Dart 3.9, but the freezed variant
advertises sdk >=3.8.0 - 1.3.8 (source_gen >=3.1.0 <5.0.0, Dart
^3.7.0) keeps 3.8 users able to resolve while 3.9+ users still get
1.3.13.

Addresses review feedback in OpenAPITools#25544.
@wing328

wing328 commented Nov 4, 2026

Copy link
Copy Markdown
Member

thanks for the PR

cc @jaumard (2018/09) @amondnet (2019/12) @sbu-WBT (2020/12) @kuhnroyal (2020/12) @agilob (2020/12) @ahmednfwela (2021/08)

@wing328 wing328 added this to the 7.28.0 milestone Nov 4, 2026
@wing328
wing328 merged commit af5fc18 into OpenAPITools:master Nov 4, 2026
30 checks passed
@wing328

wing328 commented Nov 4, 2026

Copy link
Copy Markdown
Member

lgtm. let's give it a try

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG][dart-dio] Query Path Parameters not Uri Encoded

2 participants