Skip to main content
Version: v1.1.0

circe module

Import

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

Use Drived Instances for Pre-defined Types

To make Newtype, Refined and InlinedRefined have Encoder and Decoder (or Codec) type-class instances derived from the actual values, you can simply use

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

This works only when the actual type already has Encoder and Decoder (or Codec).

info

Using refined4s.modules.circe.derivation.types.all.given is required only when Encoder and/or Decoder (or Codec) is required for the pre-defined types.
So if you want your Newtype or Refined or InlinedRefined to have Encoder and Decoder (or Codec) instances,
you can use pre-defined traits for circe or the deriving method instead.

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

import io.circe.*
import io.circe.syntax.*

def printJson[A: Encoder](a: A): Unit = println(a.asJson.spaces2)

With derivation.types.all,

import refined4s.modules.circe.derivation.types.all.given

final case class Person(name: NonEmptyString) derives Codec.AsObject

printJson(NonEmptyString("Tony Stark"))
// "Tony Stark"

val thor = Person(NonEmptyString("Thor Odinson"))
// thor: Person = Person(name = "Thor Odinson")
printJson(thor)
// {
// "name" : "Thor Odinson"
// }

val captainAmerica = Person(NonEmptyString("Steve Rogers"))
// captainAmerica: Person = Person(name = "Steve Rogers")
printJson(captainAmerica)
// {
// "name" : "Steve Rogers"
// }

import io.circe.parser.*

println(decode[Person]("""{ "name": "Kevin" }"""))
// Right(Person(Kevin))

println(decode[Person]("""{ "name": "" }"""))
// Left(DecodingFailure(Invalid value: []. It must be a non-empty String, List(DownField(name))))

With Explicit Pre-defined Circe Support

There are the following pre-defined traits to support circe' Encoder and Decoder (or Codec).

  • refined4s.modules.circe.derivation.CirceEncoder
  • refined4s.modules.circe.derivation.CirceNewtypeDecoder
  • refined4s.modules.circe.derivation.CirceRefinedDecoder
  • refined4s.modules.circe.derivation.CirceNewtypeCodec
  • refined4s.modules.circe.derivation.CirceRefinedCodec
NOTE

This works only when the actual type already has Encoder and Decoder (or Codec).

import refined4s.*
import refined4s.modules.circe.derivation.*

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

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

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

import io.circe.*

final case class Person(name: Name) derives Codec.AsObject

final case class Item(id: NotEmptyStr) derives Codec.AsObject

import io.circe.syntax.*

def printJson[A: Encoder](a: A): Unit = println(a.asJson.spaces2)
printJson(Name("Tony Stark"))
// "Tony Stark"

printJson(NotEmptyStr("Thor Odinson"))
// "Thor Odinson"

printJson(Person(Name("Steve Rogers")))
// {
// "name" : "Steve Rogers"
// }

printJson(Item(NotEmptyStr("abc-999")))
// {
// "id" : "abc-999"
// }

import io.circe.parser.*

println(decode[Person]("""{ "name": "Kevin" }"""))
// Right(Person(Kevin))

println(decode[Item]("""{ "id": "a-1234" }"""))
// Right(Item(a-1234))

println(decode[Item]("""{ "id": "" }"""))
// Left(DecodingFailure(Invalid value: []. non-empty String, List(DownField(id))))

With deriving Method

If you want to have explicit Encoder and Decoder (or Codec) 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 Encoder and Decoder (or Codec).

import cats.*

import refined4s.*
import refined4s.modules.circe.derivation.*

import io.circe.*

type Name = Name.Type
object Name extends Newtype[String] {
given encoderName: Encoder[Name] = deriving[Encoder]
given decoderName: Decoder[Name] = deriving[Decoder]
}

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 encoderNotEmptyStr: Encoder[NotEmptyStr] = deriving[Encoder]
given decoderNotEmptyStr: Decoder[NotEmptyStr] = Decoder[String].emap(NotEmptyStr.from)
}

import io.circe.*

final case class Person(name: Name) derives Codec.AsObject

final case class Item(id: NotEmptyStr) derives Codec.AsObject

import io.circe.syntax.*

def printJson[A: Encoder](a: A): Unit = println(a.asJson.spaces2)
printJson(Name("Tony Stark"))
// "Tony Stark"

printJson(NotEmptyStr("Thor Odinson"))
// "Thor Odinson"

printJson(Person(Name("Steve Rogers")))
// {
// "name" : "Steve Rogers"
// }

printJson(Item(NotEmptyStr("abc-999")))
// {
// "id" : "abc-999"
// }

import io.circe.parser.*

println(decode[Person]("""{ "name": "Kevin" }"""))
// Right(Person(Kevin))

println(decode[Item]("""{ "id": "a-1234" }"""))
// Right(Item(a-1234))

println(decode[Item]("""{ "id": "" }"""))
// Left(DecodingFailure(Invalid value: []. non-empty String, List(DownField(id))))