Skip to content

[scala-sttp4-jsoniter] support set parameters (uniqueItems arrays) in query, header, path and cookie parameters - #24301

Merged
wing328 merged 2 commits into
OpenAPITools:masterfrom
reynaldjoabet:scala-sttp4-jsoniter-set-params
Jul 15, 2026
Merged

wing328 merged 2 commits into
OpenAPITools:masterfrom
reynaldjoabet:scala-sttp4-jsoniter-set-params

Conversation

@reynaldjoabet

@reynaldjoabet reynaldjoabet commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

Parameters whose schema has uniqueItems: true are generated as Scala Set, but the serializers only matched Seq, so any Set parameter — including Set[String] — failed to compile with a Mirror.Of[Set[...]] error. This predates the enum-array work; Set was never handled.

Add Set[p] / Option[Set[p]] cases to FormSerializable, HeaderSerializable, PathSerializable and CookieSerializable. Because Set is invariant (unlike the covariant Seq), the element type is bound and dispatched on via erasedValue: primitives and enums both convert to Seq and reuse the existing array serialization, so all style/explode combinations keep working. Non-enum, non-primitive element types fail with a clear compile-time error.

Extend the sample spec with a Set of referenced enums (colors/PetColor) and a Set of primitives (uniqueTags) so the samples build exercises both paths.

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

Summary by cubic

Support Set[...] parameters in scala-sttp4-jsoniter across query, header, path, and cookie, and fix form serialization to omit empty arrays/sets. This unblocks uniqueItems arrays generated as Scala sets and avoids emitting empty param entries.

  • Bug Fixes
    • Added Set[p] and Option[Set[p]] handling to Form, Header, Path, and Cookie serializers; supports primitives and referenced enums, with unsupported element types failing at compile time.
    • Form serialization now omits empty arrays/sets when explode=false (no name=), matching explode=true and optional semantics. Updated samples/spec to cover sets: added PetColor enum and uniqueTags, and extended findPetsByTags with colors: Set[PetColor] and uniqueTags: Set[String].

Written for commit 19350b7. Summary will update on new commits.

Review in cubic

… query, header, path and cookie parameters

Parameters whose schema has `uniqueItems: true` are generated as Scala `Set`,
but the serializers only matched `Seq`, so any `Set` parameter — including
`Set[String]` — failed to compile with a `Mirror.Of[Set[...]]` error. This
predates the enum-array work; `Set` was never handled.

Add `Set[p]` / `Option[Set[p]]` cases to FormSerializable, HeaderSerializable,
PathSerializable and CookieSerializable. Because `Set` is invariant (unlike the
covariant `Seq`), the element type is bound and dispatched on via `erasedValue`:
primitives and enums both convert to `Seq` and reuse the existing array
serialization, so all style/explode combinations keep working. Non-enum,
non-primitive element types fail with a clear compile-time error.

Extend the sample spec with a `Set` of referenced enums (colors/PetColor) and a
`Set` of primitives (uniqueTags) so the samples build exercises both paths.

@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.

2 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="samples/client/petstore/scala-sttp4-jsoniter/README.md">

<violation number="1" location="samples/client/petstore/scala-sttp4-jsoniter/README.md:98">
P2: The new Models entry points to `PetColor.md`, but this generated sample does not contain that file, so the README link returns a missing page. Adding the generated model documentation (or removing this entry until it is generated) keeps the model index navigable.</violation>
</file>

<file name="samples/client/petstore/scala-sttp4-jsoniter/src/main/scala/org/openapitools/client/api/PetApi.scala">

<violation number="1" location="samples/client/petstore/scala-sttp4-jsoniter/src/main/scala/org/openapitools/client/api/PetApi.scala:134">
P2: An empty optional `colors` set is serialized as `colors=` rather than omitted. This can make a request behave differently from the OpenAPI contract (and may be rejected as an invalid empty color); guarding serialization on `colors.nonEmpty` would preserve omission semantics.</violation>
</file>

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

Re-trigger cubic

- [Category](Category.md)
- [Order](Order.md)
- [Pet](Pet.md)
- [PetColor](PetColor.md)

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: The new Models entry points to PetColor.md, but this generated sample does not contain that file, so the README link returns a missing page. Adding the generated model documentation (or removing this entry until it is generated) keeps the model index navigable.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/scala-sttp4-jsoniter/README.md, line 98:

<comment>The new Models entry points to `PetColor.md`, but this generated sample does not contain that file, so the README link returns a missing page. Adding the generated model documentation (or removing this entry until it is generated) keeps the model index navigable.</comment>

<file context>
@@ -95,6 +95,7 @@ Class | Method | HTTP request | Description
  - [Category](Category.md)
  - [Order](Order.md)
  - [Pet](Pet.md)
+ - [PetColor](PetColor.md)
  - [PetStatus](PetStatus.md)
  - [Tag](Tag.md)
</file context>

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.

this generator doesn't come with auto-generated docs for APIs and models at the moment. would be nice to have but definitely not within the scope of this change.

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.

You're right that the generator doesn't produce those API/model docs yet, so that part is out of scope for this change. The parent comment was too broad for this PR.

val requestURL =
uri"$baseUrl/pet/findByTags"
.addParams(FormSerializable.serialize("tags", tags, FormStyleFormat.FORM, false): _*)
.addParams(FormSerializable.serialize("colors", colors, FormStyleFormat.FORM, false): _*)

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: An empty optional colors set is serialized as colors= rather than omitted. This can make a request behave differently from the OpenAPI contract (and may be rejected as an invalid empty color); guarding serialization on colors.nonEmpty would preserve omission semantics.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/scala-sttp4-jsoniter/src/main/scala/org/openapitools/client/api/PetApi.scala, line 134:

<comment>An empty optional `colors` set is serialized as `colors=` rather than omitted. This can make a request behave differently from the OpenAPI contract (and may be rejected as an invalid empty color); guarding serialization on `colors.nonEmpty` would preserve omission semantics.</comment>

<file context>
@@ -121,11 +124,15 @@ case class PetApi[Auth <: org.openapitools.client.core.Authorization] private (b
     val requestURL =
       uri"$baseUrl/pet/findByTags"
         .addParams(FormSerializable.serialize("tags", tags, FormStyleFormat.FORM, false): _*)
+        .addParams(FormSerializable.serialize("colors", colors, FormStyleFormat.FORM, false): _*)
+        .addParams(FormSerializable.serialize("uniqueTags", uniqueTags, FormStyleFormat.FORM, true): _*)
 
</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.

Note: this empty-collection behavior is pre-existing, not introduced by this PR. The explode=false branch of serializeArray has always emitted name= for an empty collection (Seq(paramName -> values.map(_.asString).mkString(",")) with no empty guard), and it's shipped on master in the primitive Seq path since before the enum-array and Set work — so it already affects existing array params like status/tags, not just the new Set params. This change fixes it at the source (serializeArray), making explode=false consistent with explode=true, which already omits empty collections.

…n instead of emitting name=

    An empty array/set parameter with explode=false previously serialized as `name=`
    rather than being omitted, unlike explode=true which already dropped it. For an
    optional collection an empty value means "not provided" and should not appear in
    the request. Guard serializeArray so an empty collection yields no entries,
    making explode=false consistent with explode=true.
@wing328
wing328 merged commit 0d093a4 into OpenAPITools:master Jul 15, 2026
25 checks passed
@wing328

wing328 commented Jul 15, 2026

Copy link
Copy Markdown
Member

Thanks for the PR, which has been merged

FYI @clasnake (2017/07), @shijinkui (2018/01), @ramzimaalej (2018/03), @chameleon82 (2020/03), @Bouillie (2020/04) @Fish86 (2023/06)

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.

2 participants