Skip to main content

tapir module

Import

import refined4s.modules.tapir.derivation.types.all.given
import refined4s.modules.tapir.derivation.*

Use Drived Instances for Pre-defined Types

To make Newtype, Refined and InlinedRefined have sttp.tapir.Schema type-class instances derived from the actual values, you can simply use

import refined4s.modules.tapir.derivation.types.all.given
NOTE

This works only when the actual type already has Schema.

info

Using refined4s.modules.tapir.derivation.types.all.given is required only when sttp.tapir.Schema is required for the pre-defined types.
So if you want your Newtype or Refined or InlinedRefined to have Schema instances,
you can use pre-defined traits for tapir or the deriving method instead.

import refined4s.*
import refined4s.types.all.*

import sttp.tapir.*

def validate[A: Schema](a: A): List[ValidationError[?]] = summon[Schema[A]].applyValidation(a)
// NOTE: You don't need code like this in your project as `Schema` is required by Tapir to generate API docs so just having the Schema type-class instances is good enough.

With derivation.types.all,

import refined4s.modules.tapir.derivation.types.all.given
import sttp.tapir.generic.auto.* // It's only for case classes.

final case class Person(name: NonEmptyString)

validate(NonEmptyString("Tony Stark"))
// res1: List[ValidationError[_ >: Nothing <: Any]] = List()

val thor = Person(NonEmptyString("Thor Odinson"))
// thor: Person = Person(name = "Thor Odinson")
validate(thor)
// res2: List[ValidationError[_ >: Nothing <: Any]] = List()

With Explicit Pre-defined Tapir Support

There are the following pre-defined traits to support tapir's Schema.

  • refined4s.modules.tapir.derivation.TapirNewtypeSchema
  • refined4s.modules.tapir.derivation.TapirRefinedSchema
NOTE

This works only when the actual type already has Schema.

import refined4s.*
import refined4s.modules.tapir.derivation.*
import sttp.tapir.generic.auto.* // It's only for case classes.

type Name = Name.Type
object Name extends Newtype[String] with TapirNewtypeSchema[String]

type NotEmptyStr = NotEmptyStr.Type
object NotEmptyStr extends Refined[String] with TapirRefinedSchema[String] {
inline def invalidReason(a: String): String = "non-empty String"

inline def predicate(a: String): Boolean = a != ""
}

import sttp.tapir.*

final case class Person(name: Name)

final case class Item(id: NotEmptyStr)

def validate[A: Schema](a: A): List[ValidationError[?]] = summon[Schema[A]].applyValidation(a)
// NOTE: You don't need code like this in your project as `Schema` is required by Tapir to generate API docs so just having the Schema type-class instances is good enough.
validate(Name("Tony Stark"))
// res4: List[ValidationError[_ >: Nothing <: Any]] = List()

validate(NotEmptyStr("Thor Odinson"))
// res5: List[ValidationError[_ >: Nothing <: Any]] = List()

validate(Person(Name("Steve Rogers")))
// res6: List[ValidationError[_ >: Nothing <: Any]] = List()

validate(Item(NotEmptyStr("abc-999")))
// res7: List[ValidationError[_ >: Nothing <: Any]] = List()

With deriving Method

If you want to have explicit sttp.tapir.Schema type-class instances in your Newtype or Refined or InlinedRefined, you can use the deriving method.

NOTE

This works only when the actual type already has the Schema instance.

import cats.*

import refined4s.*
import sttp.tapir.generic.auto.* // It's only for case classes.

import sttp.tapir.*

type Name = Name.Type
object Name extends Newtype[String] {
given schemaName: Schema[Name] = deriving[Schema]
}

type NotEmptyStr = NotEmptyStr.Type
object NotEmptyStr extends Refined[String] {
inline def invalidReason(a: String): String = "non-empty String"

inline def predicate(a: String): Boolean = a != ""

given schemaNotEmptyStr: Schema[NotEmptyStr] = deriving[Schema]
}

import sttp.tapir.*

final case class Person(name: Name)

final case class Item(id: NotEmptyStr)

def validate[A: Schema](a: A): List[ValidationError[?]] = summon[Schema[A]].applyValidation(a)
// NOTE: You don't need code like this in your project as `Schema` is required by Tapir to generate API docs so just having the Schema type-class instances is good enough.
validate(Name("Tony Stark"))
// res9: List[ValidationError[_ >: Nothing <: Any]] = List()

validate(NotEmptyStr("Thor Odinson"))
// res10: List[ValidationError[_ >: Nothing <: Any]] = List()

validate(Person(Name("Steve Rogers")))
// res11: List[ValidationError[_ >: Nothing <: Any]] = List()

validate(Item(NotEmptyStr("abc-999")))
// res12: List[ValidationError[_ >: Nothing <: Any]] = List()