softwaremill / softwaremill/tapir

Comma separated values only works on scala 2.13+

Open
#3,343 4 comments 0 reactions 0 assignees View on GitHub

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 CommaSeparated is available for everyone and Delimited only for Scala 2.13+
  • Remove Delimited altogether and only keep CommaSeparated

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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.