All Downloads are FREE. Search and download functionalities are using the official Maven repository.

endpoints4s.algebra.playjson.JsonEntitiesFromCodecs.scala Maven / Gradle / Ivy

The newest version!
package endpoints4s.algebra.playjson

import endpoints4s.{Codec, Invalid, Valid, Validated}
import play.api.libs.json.{Format, JsPath, Json, JsonValidationError}

import scala.util.{Failure, Success, Try}

/** Partial interpreter for [[endpoints4s.algebra.JsonEntitiesFromCodecs]] that only
  * fixes the `JsonCodec[A]` type to Play’s `Format[A]`.
  *
  * The `jsonRequest` and `jsonResponse` operations have to be implemented by
  * a more specialized interpreter.
  *
  * Typical usage:
  *
  * {{{
  *   /* shared MyDto.scala */
  *
  *   case class MyDto(i: Int, s: String)
  *
  *   object MyDto {
  *     import play.api.libs.{Format, Json}
  *
  *     implicit val jsonFormat: Format[MyDto] = Json.format[MyDto]
  *   }
  * }}}
  *
  * {{{
  *   /* shared endpoint definition */
  *
  *   trait MyEndpoints extends algebra.Endpoints with algebra.playjson.JsonEntitiesFromCodec {
  *     val myEndpoint = endpoint(get(path), jsonResponse[MyDto])
  *   }
  * }}}
  *
  * {{{
  *   /* client MyEndpointsClient.scala */
  *
  *   object MyEndpointsClient extends MyEndpoints with xhr.JsonEntitiesFromCodec with xhr.faithful.Endpoints
  *
  *   MyEndpointsClient.myEndpoint().map(myDto => println(myDto.i))
  * }}}
  *
  * {{{
  *   /* server MyEndpointsServer.scala */
  *
  *   object MyEndpointsServer extends MyEndpoints with play.server.JsonEntitiesFromCodec {
  *
  *     val routes = routesFromEndpoints(
  *       myEndpoint.implementedBy(_ => MyDto(42, "foo"))
  *     )
  *
  *   }
  * }}}
  *
  * @group interpreters
  */
trait JsonEntitiesFromCodecs extends endpoints4s.algebra.JsonEntitiesFromCodecs {

//#type-carrier
  type JsonCodec[A] = Format[A]
//#type-carrier

  def stringCodec[A: Format]: Codec[String, A] =
    new Codec[String, A] {

      def decode(from: String): Validated[A] =
        (Try(Json.parse(from)) match {
          case Failure(_) => Left(Invalid("Unable to parse entity as JSON"))
          case Success(a) => Right(a)
        }).flatMap { json =>
          def showErrors(
              errors: collection.Seq[
                (JsPath, collection.Seq[JsonValidationError])
              ]
          ): Invalid =
            Invalid(
              (
                for {
                  (path, pathErrors) <- errors.iterator
                  error <- pathErrors
                } yield s"${error.message} for ${path.toJsonString}"
              ).toSeq
            )
          Json
            .fromJson[A](json)
            .asEither
            .left
            .map(showErrors)
            .map(Valid(_))
        }.merge

      def encode(from: A): String = Json.stringify(Json.toJson(from))

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy