Skip to content

Commit

Permalink
Merge pull request softwaremill#2382 from massimosiani/support-monix-…
Browse files Browse the repository at this point in the history
…newtypes

softwaremill#2361 add monix newtypes integration
  • Loading branch information
adamw committed Aug 30, 2022
2 parents 57d4bfd + 43f0252 commit 64cb741
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 22 deletions.
18 changes: 18 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ lazy val rawAllAggregates = core.projectRefs ++
zio1.projectRefs ++
zio.projectRefs ++
newtype.projectRefs ++
monixNewtype.projectRefs ++
circeJson.projectRefs ++
jsoniterScala.projectRefs ++
prometheusMetrics.projectRefs ++
Expand Down Expand Up @@ -598,6 +599,23 @@ lazy val newtype: ProjectMatrix = (projectMatrix in file("integrations/newtype")
)
.dependsOn(core)

lazy val monixNewtype: ProjectMatrix = (projectMatrix in file("integrations/monix-newtype"))
.settings(commonSettings)
.settings(macros)
.settings(
name := "tapir-monix-newtype",
libraryDependencies ++= Seq(
"io.monix" %%% "newtypes-core" % Versions.monixNewtype,
scalaTest.value % Test
)
)
.jvmPlatform(scalaVersions = scala2And3Versions)
.jsPlatform(
scalaVersions = scala2And3Versions,
settings = commonJsSettings
)
.dependsOn(core)

// json

lazy val circeJson: ProjectMatrix = (projectMatrix in file("json/circe"))
Expand Down
15 changes: 13 additions & 2 deletions doc/endpoint/integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,24 @@ Tapir `Schema` for any `Enumeration.Value` can also be auto or semi-auto derived
## NewType integration

If you use [scala-newtype](https://github.com/estatico/scala-newtype), the `tapir-newtype` module will provide implicit codecs and
schemas for a types with a `@newtype` and `@newsubtype` annotations as long as a codec and schema for its underlying value already exists:
schemas for types with a `@newtype` and `@newsubtype` annotations as long as a codec and schema for its underlying value already exists:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-newtype" % "@VERSION@"
```

Then, `import sttp.tapir.codec.newtype._`, or extend the `sttp.tapir.codec.enumeratum.TapirCodecNewType` trait to bring the implicit values into scope.
Then, `import sttp.tapir.codec.newtype._`, or extend the `sttp.tapir.codec.newtype.TapirCodecNewType` trait to bring the implicit values into scope.

## Monix NewType integration

If you use [monix newtypes](https://github.com/monix/newtypes), the `tapir-monix-newtype` module will provide implicit codecs and
schemas for types which extend `NewtypeWrapped` and `NewsubtypeWrapped` annotations as long as a codec and schema for its underlying value already exists:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-monix-newtype" % "@VERSION@"
```

Then, `import sttp.tapir.codec.monix.newtype._`, or extend the `sttp.tapir.codec.monix.newtype.TapirCodecMonixNewType` trait to bring the implicit values into scope.

## Derevo integration

Expand Down
19 changes: 10 additions & 9 deletions doc/stability.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,16 @@ The modules are categorised using the following levels:

## Integration modules

| Module | Level |
|------------|--------------|
| cats | stabilising |
| derevo | stabilising |
| enumeratum | stabilising |
| newtype | stabilising |
| refined | stabilising |
| zio | experimental |
| zio1 | stabilising |
| Module | Level |
|------------------|--------------|
| cats | stabilising |
| derevo | stabilising |
| enumeratum | stabilising |
| newtype | stabilising |
| monix-newtype | stabilising |
| refined | stabilising |
| zio | experimental |
| zio1 | stabilising |

## JSON modules

Expand Down
15 changes: 13 additions & 2 deletions generated-doc/out/endpoint/integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,24 @@ Tapir `Schema` for any `Enumeration.Value` can also be auto or semi-auto derived
## NewType integration

If you use [scala-newtype](https://github.com/estatico/scala-newtype), the `tapir-newtype` module will provide implicit codecs and
schemas for a types with a `@newtype` and `@newsubtype` annotations as long as a codec and schema for its underlying value already exists:
schemas for types with a `@newtype` and `@newsubtype` annotations as long as a codec and schema for its underlying value already exists:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-newtype" % "1.0.6"
```

Then, `import sttp.tapir.codec.newtype._`, or extend the `sttp.tapir.codec.enumeratum.TapirCodecNewType` trait to bring the implicit values into scope.
Then, `import sttp.tapir.codec.newtype._`, or extend the `sttp.tapir.codec.newtype.TapirCodecNewType` trait to bring the implicit values into scope.

## Monix NewType integration

If you use [monix newtypes](https://github.com/monix/newtypes), the `tapir-monix-newtype` module will provide implicit codecs and
schemas for types which extend `NewtypeWrapped` and `NewsubtypeWrapped` annotations as long as a codec and schema for its underlying value already exists:

```scala
"com.softwaremill.sttp.tapir" %% "tapir-monix-newtype" % "1.0.6"
```

Then, `import sttp.tapir.codec.monix.newtype._`, or extend the `sttp.tapir.codec.monix.newtype.TapirCodecMonixNewType` trait to bring the implicit values into scope.

## Derevo integration

Expand Down
19 changes: 10 additions & 9 deletions generated-doc/out/stability.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,16 @@ The modules are categorised using the following levels:

## Integration modules

| Module | Level |
|------------|--------------|
| cats | stabilising |
| derevo | stabilising |
| enumeratum | stabilising |
| newtype | stabilising |
| refined | stabilising |
| zio | experimental |
| zio1 | stabilising |
| Module | Level |
|------------------|--------------|
| cats | stabilising |
| derevo | stabilising |
| enumeratum | stabilising |
| newtype | stabilising |
| monix-newtype | stabilising |
| refined | stabilising |
| zio | experimental |
| zio1 | stabilising |

## JSON modules

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package sttp.tapir.codec.monix.newtype

import monix.newtypes.{HasBuilder, HasExtractor}
import sttp.tapir._

trait TapirCodecMonixNewType {
implicit def schemaForMonixNewType[T, S](implicit ev1: HasExtractor.Aux[T, S], ev2: HasBuilder.Aux[T, S], schema: Schema[S]): Schema[T] =
schema.map(ev2.build(_).toOption)(ev1.extract(_))

implicit def codecForMonixNewType[L, A, B, CF <: CodecFormat](implicit
ev1: HasExtractor.Aux[B, A],
ev2: HasBuilder.Aux[B, A],
codec: Codec[L, A, CF]
): Codec[L, B, CF] =
codec.mapDecode(v => DecodeResult.fromEitherString(v.toString, ev2.build(v).left.map(_.toReadableString)))(ev1.extract(_))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package sttp.tapir.codec.monix

package object newtype extends TapirCodecMonixNewType
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package sttp.tapir.codec.monix.newtype

import monix.newtypes._
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import sttp.tapir.Codec.PlainCodec
import sttp.tapir.CodecFormat.TextPlain
import sttp.tapir.DecodeResult.Value
import sttp.tapir.{Codec, Schema}

class TapirCodecMonixNewTypeTest extends AnyFlatSpec with Matchers {
import TapirCodecMonixNewTypeTest._

it should "find schema for newtype which is equal to the schema of its underlying value" in {
implicitly[Schema[Foo]] shouldBe Schema.schemaForString
}

it should "find schema for newsubtype which is equal to the schema of its underlying value" in {
implicitly[Schema[Bar]] shouldBe Schema.schemaForInt
}

"Provided PlainText codec for a newtype" should "equal to the codec of its underlying value" in {
val newTypeCodec = implicitly[PlainCodec[Foo]]
newTypeCodec.schema shouldBe Codec.string.schema
newTypeCodec.format shouldBe Codec.string.format
}

it should "correctly deserialize everything it serialize" in {
val newTypeCodec = implicitly[Codec[String, Foo, TextPlain]]
val foo = Foo("foo")

newTypeCodec.decode(newTypeCodec.encode(foo)) shouldBe Value(foo)
}

"Provided PlainText codec for a newsubtype" should "equal to the codec of its underlying value" in {
val newSubTypeCodec = implicitly[PlainCodec[Bar]]
newSubTypeCodec.schema shouldBe Codec.int.schema
newSubTypeCodec.format shouldBe Codec.int.format
}

it should "correctly deserialize everything it serialize" in {
val newSubTypeCodec = implicitly[PlainCodec[Bar]]
val bar = Bar(1)

newSubTypeCodec.decode(newSubTypeCodec.encode(bar)) shouldBe Value(bar)
}

}

object TapirCodecMonixNewTypeTest {
type Foo = Foo.Type
object Foo extends NewtypeWrapped[String]

type Bar = Bar.Type
object Bar extends NewsubtypeWrapped[Int]
}
1 change: 1 addition & 0 deletions project/Versions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ object Versions {
val jwtScala = "5.0.0"
val derevo = "0.13.0"
val newtype = "0.4.4"
val monixNewtype = "0.2.3"
val awsLambdaInterface = "2.1.1"
val armeria = "1.18.0"
val scalaJava8Compat = "1.0.2"
Expand Down

0 comments on commit 64cb741

Please sign in to comment.