softwaremill / softwaremill/tapir
Comma separated values only works on scala 2.13+
Nobody has claimed this yet.
- Dominant language
- Scala
- Stars
- 1.5k
- Forks
- 468
- Avg merge
- 5h 37m
- Merged PRs (30d)
- 34
Description
Tapir version: 1.9.2
Hi peps!
Context
A very common use case when defining an endpoint is adding an (optional) filter of "categories".
One way of doing so is as a list of comma-separated values, like
GET /tapirs?cute=true&breed=malayan,baird
Tapir, after this discussion, provides the handy CommaSeparatedValues.
This work perfectly, and the openapi documentation is generated as one would expect in the case of enumerations (with allowedValues).
The problem
The issue with this is that CommaSeparated is defined as
type CommaSeparated[T] = Delimited[",", T]
Unfortunately, type literals are only supported in Scala 2.13+. Which means, people using previous versions of Scala can't use this feature :(
One possible solution
The most trivial solution is just to hard-code the comma in CommaSeparated, of course
final case class CommaSeparated[T](values: List[T])
/** Creates a codec which handles values delimited using `,`. The implicit `T`-codec is used for handling each individual value.
*
* Upon decoding, the string is split using the delimiter, and then decoded using the `T`-codec. Upon encoding, the values are first
* encoded using the `T`-codec, and then combined using the delimiter.
*
* The codec's schema has the `explode` attribute set to `false`.
*/
implicit def commaSeparated[T](
implicit
codec: Codec[String, T, CodecFormat.TextPlain]
): Codec[String, CommaSeparated[T], CodecFormat.TextPlain] =
Codec.string
.map(_.split(",").toList)(_.mkString(","))
.mapDecode(ls => DecodeResult.sequence(ls.map(codec.decode)).map(_.toList))(_.map(codec.encode))
.schema(codec.schema.asIterable[List].attribute(Schema.Explode.Attribute, Schema.Explode(false)))
.map(CommaSeparated[T](_))(_.values)
implicit def schemaForCommaSeparated[D <: String, T](
implicit
tSchema: Schema[T]
): Schema[CommaSeparated[T]] =
tSchema.asIterable[List].map(l => Some(CommaSeparated[T](l)))(_.values).attribute(Explode.Attribute, Explode(false))
The disadvantage is that we'd not be reusing the exact same code we use for Delimited.
What to do next?
I personally see a few options
- Do nothing code-wise, but specify that the feature is only available in Scala 2.13 in the documentation
- Duplicate the code so that
CommaSeparatedis available for everyone andDelimitedonly for Scala 2.13+ - Remove
Delimitedaltogether and only keepCommaSeparated
The third option is quite extreme and causes a breaking change of course.
On the other hand, I don't see a real use case for anything other than comma (though clearly you do, so perhaps it's just inexperience on my part), and by making this more generic we're sacrificing the functionality for an interesting portion of Scala users (according to this 2022 survery, about 40% of Scala users still use 2.12 in some projects).
Do we have any kind of metric about how needed this functionality is?
Thanks for reading!
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the CommaSeparated and Delimited definitions described in the issue and the linked lists-of-enumeration-values documentation. Check how their type aliases interact with the supported Scala versions, then determine which compatibility approach the maintainers want. Done means an agreed implementation or documentation change, with behavior and Scala-version support clearly covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- scala
- Domain
- api, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100