Last active
October 2, 2017 10:58
-
-
Save ferhtaydn/72cc8820a5a14f0aa8b5a9ebad016089 to your computer and use it in GitHub Desktop.
How to serialize NonEmptyList in model like normal List
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cats.Applicative | |
import cats.data.{NonEmptyList => NEL} | |
import cats.syntax.traverse._ | |
import play.api.libs.json._ | |
final case class Error(code: String, description: String) | |
object Error { | |
implicit object jsResultApplicative extends Applicative[JsResult] { | |
override def pure[A](x: A): JsResult[A] = | |
JsResult.applicativeJsResult.pure(x) | |
override def ap[A, B]( | |
ff: JsResult[(A) => B] | |
)(fa: JsResult[A]): JsResult[B] = | |
JsResult.applicativeJsResult.apply(ff, fa) | |
} | |
implicit val errorFormat: OFormat[Error] = | |
Json.format[Error] | |
implicit val nelErrorReads: Reads[NEL[Error]] = Reads { | |
case JsArray(errors) => | |
errors.toList match { | |
case head :: tail => | |
NEL( | |
head.validate[Error], | |
tail.map(_.validate[Error]) | |
).sequence[JsResult, Error] | |
case Nil => JsError("expected a NonEmptyList but got empty list") | |
} | |
case other: JsValue => | |
JsError(s"expected an array but got ${other.toString}") | |
} | |
implicit val nelErrorWrites: Writes[NEL[Error]] = Writes { nelErrors => | |
Json.toJson(nelErrors.toList) | |
} | |
} | |
final case class ErrorResponse(errors: NEL[Error]) | |
object ErrorResponse { | |
def apply(code: String, desc: String): ErrorResponse = | |
ErrorResponse(NEL.of(Error(code, desc))) | |
implicit val errorResponseFormat: OFormat[ErrorResponse] = | |
Json.format[ErrorResponse] | |
} | |
object Usage { | |
val nelToJsonString = | |
""" | |
|{ | |
| "errors": { | |
| "head": { | |
| "code": "someCode", | |
| "description": "someDesc" | |
| }, | |
| "tail": [] | |
| } | |
|} | |
""".stripMargin | |
val er = ErrorResponse("someCode", "someDesc") | |
val erJSon = Json.toJson(er) | |
val erJsonString = | |
""" | |
|{ | |
| "errors": [ | |
| { | |
| "code": "someCode", | |
| "description": "someDesc" | |
| } | |
| ] | |
|} | |
""".stripMargin | |
val er2 = ErrorResponse( | |
NEL.of( | |
Error("someCode", "someDesc"), | |
Error("someCode2", "someDesc2") | |
) | |
) | |
val er2Json = Json.toJson(er2) | |
val er2JsonString = """ | |
|{ | |
| "errors": [ | |
| { | |
| "code": "someCode", | |
| "description": "someDesc" | |
| }, | |
| { | |
| "code": "someCode2", | |
| "description": "someDesc2" | |
| } | |
| ] | |
|} | |
""".stripMargin | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cats.Applicative | |
import cats.data.{NonEmptyList => NEL} | |
import cats.syntax.traverse._ | |
import play.api.libs.json._ | |
object NonEmptyListOps { | |
implicit object jsResultApplicative extends Applicative[JsResult] { | |
override def pure[A](x: A): JsResult[A] = | |
JsResult.applicativeJsResult.pure(x) | |
override def ap[A, B]( | |
ff: JsResult[(A) => B] | |
)(fa: JsResult[A]): JsResult[B] = | |
JsResult.applicativeJsResult.apply(ff, fa) | |
} | |
def reads[T: Reads]: Reads[NEL[T]] = Reads { | |
case JsArray(elems) => | |
elems.toList match { | |
case head :: tail => | |
NEL( | |
head.validate[T], | |
tail.map(_.validate[T]) | |
).sequence[JsResult, T] | |
case Nil => JsError("expected a NonEmptyList but got empty list") | |
} | |
case other: JsValue => | |
JsError(s"expected an array but got ${other.toString}") | |
} | |
def writes[T: Writes]: Writes[NEL[T]] = Writes { elems => | |
Json.toJson(elems.toList) | |
} | |
def format[T: Format]: Format[NEL[T]] = Format(reads[T], writes[T]) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cats.data.{NonEmptyList => NEL} | |
import play.api.libs.functional.syntax._ | |
import play.api.libs.json._ | |
object NonEmptyListOps { | |
def reads[T: Reads]: Reads[NEL[T]] = | |
Reads | |
.of[List[T]] | |
.collect( | |
JsonValidationError("expected a NonEmptyList but got an empty list") | |
) { | |
case head :: tail => NEL(head, tail) | |
} | |
def writes[T: Writes]: Writes[NEL[T]] = | |
Writes | |
.of[List[T]] | |
.contramap(_.toList) | |
def format[T: Format]: Format[NEL[T]] = | |
Format(reads, writes) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment