akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller Scala Examples

The following examples show how to use akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: AkkaHttpLambdaHandlerSpec.scala    From scala-server-lambda   with MIT License 5 votes vote down vote up
package io.github.howardjohn.lambda.akka

import akka.actor.ActorSystem
import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
import akka.http.scaladsl.model.MediaTypes.`application/json`
import akka.http.scaladsl.model.headers.RawHeader
import akka.http.scaladsl.model.{HttpEntity, StatusCodes}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import akka.stream.ActorMaterializer
import io.circe.parser.decode
import io.circe.syntax._
import io.circe.{Decoder, Encoder}
import io.github.howardjohn.lambda.LambdaHandlerBehavior
import io.github.howardjohn.lambda.LambdaHandlerBehavior._
import org.scalatest.{BeforeAndAfterAll, FeatureSpec, GivenWhenThen}

import scala.concurrent.Future

class AkkaHttpLambdaHandlerSpec
    extends FeatureSpec
    with LambdaHandlerBehavior
    with GivenWhenThen
    with BeforeAndAfterAll {

  implicit val system: ActorSystem = ActorSystem("test")
  implicit val materializer: ActorMaterializer = ActorMaterializer()
  implicit val ec = scala.concurrent.ExecutionContext.Implicits.global

  val route: Route =
    path("hello") {
      (get & parameter("times".as[Int] ? 1)) { times =>
        complete {
          Seq
            .fill(times)("Hello World!")
            .mkString(" ")
        }
      }
    } ~ path("long") {
      get {
        Thread.sleep(1000)
        complete("")
      }
    } ~ path("post") {
      post {
        entity(as[String]) { body =>
          complete(body)
        }
      }
    } ~ path("json") {
      post {
        import CirceJsonMarshalling._
        import io.circe.generic.auto._
        entity(as[JsonBody]) { entity =>
          complete(LambdaHandlerBehavior.jsonReturn.asJson)
        }
      }
    } ~ path("exception") {
      get {
        throw RouteException()
      }
    } ~ path("error") {
      get {
        complete(StatusCodes.InternalServerError)
      }
    } ~ path("header") {
      get {
        headerValueByName(inputHeader) { header =>
          respondWithHeaders(RawHeader(outputHeader, outputHeaderValue)) {
            complete(header)
          }
        }
      }
    }

  val handler = new AkkaHttpLambdaHandler(route)

  scenariosFor(behavior(handler))

  override def afterAll(): Unit = {
    materializer.shutdown()
    system.terminate()
  }
}


object CirceJsonMarshalling {
  implicit final def unmarshaller[A: Decoder]: FromEntityUnmarshaller[A] =
    Unmarshaller.stringUnmarshaller
      .forContentTypes(`application/json`)
      .flatMap { ctx => mat => json =>
        decode[A](json).fold(Future.failed, Future.successful)
      }

  implicit final def marshaller[A: Encoder]: ToEntityMarshaller[A] =
    Marshaller.withFixedContentType(`application/json`) { a =>
      HttpEntity(`application/json`, a.asJson.noSpaces)
    }
} 
Example 2
Source File: PlayJsonSupport.scala    From akka-cluster-manager   with MIT License 5 votes vote down vote up
package io.orkestra.cluster.management

import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
import akka.http.scaladsl.model.HttpCharsets
import akka.http.scaladsl.model.MediaTypes.`application/json`
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import akka.stream.Materializer
import play.api.libs.json._

import scala.concurrent.ExecutionContext
import scala.language.implicitConversions


trait PlayJsonSupport {

  type Printer = (JsValue ⇒ String)

  def read[T](jsValue: JsValue)(implicit reads: Reads[T]): T = {
    reads.reads(jsValue) match {
      case s: JsSuccess[T] ⇒ s.get
      case e: JsError ⇒ throw JsResultException(e.errors)
    }
  }

  implicit def playJsonUnmarshallerConverter[T](reads: Reads[T])(implicit ec: ExecutionContext, mat: Materializer): FromEntityUnmarshaller[T] =
    playJsonUnmarshaller(reads, ec, mat)

  implicit def playJsonUnmarshaller[T](implicit reads: Reads[T], ec: ExecutionContext, mat: Materializer): FromEntityUnmarshaller[T] =
    playJsValueUnmarshaller.map(read[T])

  implicit def playJsValueUnmarshaller(implicit ec: ExecutionContext, mat: Materializer): FromEntityUnmarshaller[JsValue] =
    Unmarshaller.byteStringUnmarshaller.forContentTypes(`application/json`).mapWithCharset { (data, charset) ⇒
      if (charset == HttpCharsets.`UTF-8`) Json.parse(data.toArray)
      else Json.parse(data.decodeString(charset.nioCharset.name)) // FIXME: identify charset by instance, not by name!
    }

  implicit def playJsonMarshallerConverter[T](writes: Writes[T])(implicit printer: Printer = Json.prettyPrint, ec: ExecutionContext): ToEntityMarshaller[T] =
    playJsonMarshaller[T](writes, printer, ec)

  implicit def playJsonMarshaller[T](implicit writes: Writes[T], printer: Printer = Json.prettyPrint, ec: ExecutionContext): ToEntityMarshaller[T] =
    playJsValueMarshaller[T].compose(writes.writes)

  implicit def playJsValueMarshaller[T](implicit writes: Writes[T], printer: Printer = Json.prettyPrint, ec: ExecutionContext): ToEntityMarshaller[JsValue] =
    Marshaller.StringMarshaller.wrap(`application/json`)(printer)
}

object PlayJsonSupport extends PlayJsonSupport 
Example 3
Source File: JsonUnmarshallers.scala    From scala-openrtb   with Apache License 2.0 5 votes vote down vote up
package com.powerspace.openrtb.akka.marshallers

import akka.http.scaladsl.model.{ContentTypeRange, ContentTypes, HttpRequest}
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, FromRequestUnmarshaller, Unmarshaller}
import akka.stream.Materializer
import com.google.openrtb.{BidRequest, BidResponse}
import io.circe.Decoder

import scala.concurrent.{ExecutionContext, Future}
import io.circe.parser.decode

object JsonUnmarshallers {

  import akka.http.scaladsl.unmarshalling.PredefinedFromEntityUnmarshallers._

  def bidRequestJsonUnmarshaller(implicit decoder: Decoder[BidRequest]): FromEntityUnmarshaller[BidRequest] =
    stringUnmarshaller
      .forContentTypes(ContentTypeRange(ContentTypes.`application/json`))
      .map(implicit json => decode[BidRequest](json).handlingFailure)

  def bidResponseJsonUnmarshaller(implicit decoder: Decoder[BidResponse]): FromEntityUnmarshaller[BidResponse] =
    stringUnmarshaller
      .forContentTypes(ContentTypeRange(ContentTypes.`application/json`))
      .map(implicit json => decode[BidResponse](json).handlingFailure)

  def bidRequestHttpJsonUnmarshaller(implicit decoder: Decoder[BidRequest]): FromRequestUnmarshaller[BidRequest] =
    new FromRequestUnmarshaller[BidRequest]() {
      override def apply(
        value: HttpRequest)(implicit ec: ExecutionContext, materializer: Materializer): Future[BidRequest] =
        Unmarshaller
          .stringUnmarshaller(value.entity)
          .map(implicit json => decode[BidRequest](json).handlingFailure)
    }

  def bidResponseHttpJsonUnmarshaller(implicit decoder: Decoder[BidResponse]): FromRequestUnmarshaller[BidResponse] =
    new FromRequestUnmarshaller[BidResponse]() {
      override def apply(
        value: HttpRequest)(implicit ec: ExecutionContext, materializer: Materializer): Future[BidResponse] =
        Unmarshaller
          .stringUnmarshaller(value.entity)
          .map(implicit json => decode[BidResponse](json).handlingFailure)
    }

  implicit class DecodingResultEnhancement[T](decodingResult: Either[_ <: Exception, T]) {

    def handlingFailure(implicit json: String): T = decodingResult match {
      case Right(decoded) => decoded
      case Left(error) => throw new UnsupportedOperationException(error)
    }
  }

} 
Example 4
Source File: UpickleCustomizationSupport.scala    From akka-http-json   with Apache License 2.0 5 votes vote down vote up
package de.heikoseeberger.akkahttpupickle

import akka.http.javadsl.common.JsonEntityStreamingSupport
import akka.http.scaladsl.common.EntityStreamingSupport
import akka.http.scaladsl.marshalling.{ Marshaller, Marshalling, ToEntityMarshaller }
import akka.http.scaladsl.model.{ ContentTypeRange, HttpEntity, MediaType, MessageEntity }
import akka.http.scaladsl.model.MediaTypes.`application/json`
import akka.http.scaladsl.unmarshalling.{ FromEntityUnmarshaller, Unmarshal, Unmarshaller }
import akka.http.scaladsl.util.FastFuture
import akka.stream.scaladsl.{ Flow, Source }
import akka.util.ByteString
import UpickleCustomizationSupport._

import scala.collection.immutable.Seq
import scala.concurrent.Future
import scala.util.Try
import scala.util.control.NonFatal

// This companion object only exists for binary compatibility as adding methods with default implementations
// (including val's as they create synthetic methods) is not compatible.
private object UpickleCustomizationSupport {

  private def jsonStringUnmarshaller(support: UpickleCustomizationSupport) =
    Unmarshaller.byteStringUnmarshaller
      .forContentTypes(support.unmarshallerContentTypes: _*)
      .mapWithCharset {
        case (ByteString.empty, _) => throw Unmarshaller.NoContentException
        case (data, charset)       => data.decodeString(charset.nioCharset.name)
      }

  private def jsonSourceStringMarshaller(support: UpickleCustomizationSupport) =
    Marshaller.oneOf(support.mediaTypes: _*)(support.sourceByteStringMarshaller)

  private def jsonStringMarshaller(support: UpickleCustomizationSupport) =
    Marshaller.oneOf(support.mediaTypes: _*)(Marshaller.stringMarshaller)
}


  implicit def sourceMarshaller[A](implicit
      writes: apiInstance.Writer[A],
      support: JsonEntityStreamingSupport = EntityStreamingSupport.json()
  ): ToEntityMarshaller[SourceOf[A]] =
    jsonSourceStringMarshaller(this).compose(jsonSource[A])
} 
Example 5
Source File: GenCodecSupport.scala    From akka-http-json   with Apache License 2.0 5 votes vote down vote up
package de.heikoseeberger.akkahttpavsystemgencodec

import akka.http.scaladsl.marshalling.{ Marshaller, ToEntityMarshaller }
import akka.http.scaladsl.model.ContentTypeRange
import akka.http.scaladsl.model.MediaType
import akka.http.scaladsl.model.MediaTypes.`application/json`
import akka.http.scaladsl.unmarshalling.{ FromEntityUnmarshaller, Unmarshaller }
import akka.util.ByteString
import com.avsystem.commons.serialization.GenCodec
import com.avsystem.commons.serialization.json.{ JsonStringInput, JsonStringOutput }

import scala.collection.immutable.Seq

object GenCodecSupport extends GenCodecSupport {}

trait GenCodecSupport {

  def unmarshallerContentTypes: Seq[ContentTypeRange] =
    mediaTypes.map(ContentTypeRange.apply)

  def mediaTypes: Seq[MediaType.WithFixedCharset] =
    List(`application/json`)

  private val jsonStringUnmarshaller =
    Unmarshaller.byteStringUnmarshaller
      .forContentTypes(unmarshallerContentTypes: _*)
      .mapWithCharset {
        case (ByteString.empty, _) => throw Unmarshaller.NoContentException
        case (data, charset)       => data.decodeString(charset.nioCharset.name)
      }

  private val jsonStringMarshaller =
    Marshaller.oneOf(mediaTypes: _*)(Marshaller.stringMarshaller)

  
  implicit def marshaller[A: GenCodec]: ToEntityMarshaller[A] =
    jsonStringMarshaller.compose(JsonStringOutput.write(_))
} 
Example 6
Source File: JsonBackend.scala    From caliban   with Apache License 2.0 5 votes vote down vote up
package caliban

import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller


trait JsonBackend {
  def parseHttpRequest(
    query: Option[String],
    op: Option[String],
    vars: Option[String],
    exts: Option[String]
  ): Either[Throwable, GraphQLRequest]
  def encodeGraphQLResponse(r: GraphQLResponse[Any]): String

  def parseWSMessage(text: String): Either[Throwable, WSMessage]
  def encodeWSResponse[E](id: String, data: ResponseValue, errors: List[E]): String
  def encodeWSError(id: String, error: Throwable): String

  def reqUnmarshaller: FromEntityUnmarshaller[GraphQLRequest]

} 
Example 7
Source File: CirceJsonBackend.scala    From caliban   with Apache License 2.0 5 votes vote down vote up
package caliban.interop.circe

import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller
import caliban._
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport
import io.circe.Json
import io.circe.parser._
import io.circe.syntax._


final class CirceJsonBackend extends JsonBackend with FailFastCirceSupport {
  def parseHttpRequest(
    query: Option[String],
    op: Option[String],
    vars: Option[String],
    exts: Option[String]
  ): Either[Throwable, GraphQLRequest] = {
    val variablesJs  = vars.flatMap(parse(_).toOption)
    val extensionsJs = exts.flatMap(parse(_).toOption)
    val fields = query.map(js => "query" -> Json.fromString(js)) ++
      op.map(o => "operationName"         -> Json.fromString(o)) ++
      variablesJs.map(js => "variables"   -> js) ++
      extensionsJs.map(js => "extensions" -> js)
    Json
      .fromFields(fields)
      .as[GraphQLRequest]
  }

  def encodeGraphQLResponse(r: GraphQLResponse[Any]): String = r.asJson.toString()

  def parseWSMessage(text: String): Either[Throwable, WSMessage] =
    decode[Json](text).map(json =>
      CirceWSMessage(
        json.hcursor.downField("id").success.flatMap(_.value.asString).getOrElse(""),
        json.hcursor.downField("type").success.flatMap(_.value.asString).getOrElse(""),
        json.hcursor.downField("payload")
      )
    )

  def encodeWSResponse[E](id: String, data: ResponseValue, errors: List[E]): String =
    Json
      .obj(
        "id"      -> Json.fromString(id),
        "type"    -> Json.fromString("data"),
        "payload" -> GraphQLResponse(data, errors).asJson
      )
      .noSpaces

  def encodeWSError(id: String, error: Throwable): String =
    Json
      .obj(
        "id"      -> Json.fromString(id),
        "type"    -> Json.fromString("complete"),
        "payload" -> Json.fromString(error.toString)
      )
      .noSpaces

  def reqUnmarshaller: FromEntityUnmarshaller[GraphQLRequest] = implicitly
} 
Example 8
Source File: PlayJsonBackend.scala    From caliban   with Apache License 2.0 5 votes vote down vote up
package caliban.interop.play

import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller
import caliban._
import caliban.interop.play.json.parsingException
import de.heikoseeberger.akkahttpplayjson.PlayJsonSupport
import play.api.libs.json.{ JsObject, JsValue, Json }
import scala.util.Try


final class PlayJsonBackend extends JsonBackend with PlayJsonSupport {

  private def parseJson(s: String): Try[JsValue] =
    Try(Json.parse(s))

  def parseHttpRequest(
    query: Option[String],
    op: Option[String],
    vars: Option[String],
    exts: Option[String]
  ): Either[Throwable, GraphQLRequest] = {
    val variablesJs  = vars.flatMap(parseJson(_).toOption)
    val extensionsJs = exts.flatMap(parseJson(_).toOption)
    Json
      .obj(
        "query"         -> query,
        "operationName" -> op,
        "variables"     -> variablesJs,
        "extensions"    -> extensionsJs
      )
      .validate[GraphQLRequest]
      .asEither
      .left
      .map(parsingException)
  }

  def encodeGraphQLResponse(r: GraphQLResponse[Any]): String = Json.toJson(r).toString()

  def parseWSMessage(text: String): Either[Throwable, WSMessage] =
    parseJson(text).toEither.map { json =>
      PlayWSMessage(
        (json \ "id").validate[String].getOrElse(""),
        (json \ "type").validate[String].getOrElse(""),
        (json \ "payload").validate[JsObject].asOpt
      )
    }

  def encodeWSResponse[E](id: String, data: ResponseValue, errors: List[E]): String =
    Json.stringify(
      Json
        .obj(
          "id"      -> id,
          "type"    -> "data",
          "payload" -> GraphQLResponse(data, errors)
        )
    )

  def encodeWSError(id: String, error: Throwable): String =
    Json.stringify(
      Json
        .obj(
          "id"      -> id,
          "type"    -> "complete",
          "payload" -> error.toString
        )
    )

  def reqUnmarshaller: FromEntityUnmarshaller[GraphQLRequest] = implicitly
} 
Example 9
Source File: Json4sSupport.scala    From service-container   with Apache License 2.0 5 votes vote down vote up
package com.github.vonnagy.service.container.http.json

import java.lang.reflect.InvocationTargetException

import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
import akka.http.scaladsl.model.MediaTypes.`application/json`
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import akka.util.ByteString
import org.json4s.JsonAST.JValue
import org.json4s.{Formats, MappingException, Serialization}


  implicit def json4sMarshaller[A <: AnyRef](
                                              implicit serialization: Serialization,
                                              formats: Formats,
                                              shouldWritePretty: ShouldWritePretty = ShouldWritePretty.False
                                            ): ToEntityMarshaller[A] = {
    shouldWritePretty match {
      case ShouldWritePretty.False =>
        jsonStringMarshaller.compose(serialization.write[A])
      case ShouldWritePretty.True =>
        jsonStringMarshaller.compose(serialization.writePretty[A])
    }
  }

  implicit def json4sJValueMarshaller[A <: JValue](
                                                    implicit serialization: Serialization,
                                                    formats: Formats,
                                                    shouldWritePretty: ShouldWritePretty = ShouldWritePretty.False
                                                  ): ToEntityMarshaller[A] = {

    shouldWritePretty match {
      case ShouldWritePretty.False =>
        jsonStringMarshaller.compose(serialization.write[A])
      case ShouldWritePretty.True =>
        jsonStringMarshaller.compose(serialization.writePretty[A])
    }
  }
} 
Example 10
Source File: JsonSupport.scala    From akka-stream-json   with Apache License 2.0 5 votes vote down vote up
package de.knutwalker.akka.http

import de.knutwalker.akka.stream.JsonStreamParser

import akka.http.scaladsl.model.HttpEntity
import akka.http.scaladsl.model.MediaTypes.`application/json`
import akka.http.scaladsl.unmarshalling.{ FromEntityUnmarshaller, Unmarshaller }
import akka.http.scaladsl.util.FastFuture
import akka.stream.scaladsl.Sink
import akka.stream.stage.{ GraphStageLogic, GraphStageWithMaterializedValue, InHandler }
import akka.stream.{ AbruptStageTerminationException, Attributes, Inlet, SinkShape }

import jawn.Facade

import scala.concurrent.{ Future, Promise }
import java.util.NoSuchElementException

object JsonSupport extends JsonSupport {
  private def firstElementSink[J <: AnyRef]: Sink[J, Future[J]] =
    Sink.fromGraph(new FirstElementSinkStage[J])

  private final class FirstElementSinkStage[J <: AnyRef] extends GraphStageWithMaterializedValue[SinkShape[J], Future[J]] {
    private[this] val in: Inlet[J] = Inlet("firstElement.in")

    override val shape: SinkShape[J] = SinkShape.of(in)
    override protected def initialAttributes: Attributes = Attributes.name("firstElement")

    override def createLogicAndMaterializedValue(inheritedAttributes: Attributes): (GraphStageLogic, Future[J]) = {
      val p: Promise[J] = Promise()
      (new GraphStageLogic(shape) with InHandler {
        private[this] var element: J = null.asInstanceOf[J]

        override def preStart(): Unit = pull(in)

        def onPush(): Unit = {
          if (element eq null) {
            element = grab(in)
          }
          pull(in)
        }

        override def onUpstreamFinish(): Unit = {
          val el = element
          element = null.asInstanceOf[J]
          if (el ne null) {
            p.trySuccess(el)
          } else {
            p.tryFailure(new NoSuchElementException("No complete json entity consumed"))
          }
          completeStage()
        }

        override def onUpstreamFailure(ex: Throwable): Unit = {
          element = null.asInstanceOf[J]
          p.tryFailure(ex)
          failStage(ex)
        }

        override def postStop(): Unit = {
          if (!p.isCompleted) {
            p.failure(new AbruptStageTerminationException(this))
            ()
          }
        }

        setHandler(in, this)
      }, p.future)
    }

    override def toString: String = "FirstElementSinkStage"
  }
}

trait JsonSupport {

  implicit def jsonUnmarshaller[J <: AnyRef : Facade]: FromEntityUnmarshaller[J] =
    Unmarshaller.withMaterializer[HttpEntity, J](_ => implicit mat => {
      case HttpEntity.Strict(_, data) => FastFuture(JsonStreamParser.parse[J](data))
      case entity                     => entity.dataBytes.via(JsonStreamParser[J]).runWith(JsonSupport.firstElementSink[J])
    }).forContentTypes(`application/json`)
} 
Example 11
Source File: GraphQLRequestUnmarshaller.scala    From graphql-gateway   with Apache License 2.0 5 votes vote down vote up
package sangria.gateway.http

import java.nio.charset.Charset

import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
import akka.http.scaladsl.model._
import akka.http.scaladsl.model.headers.Accept
import akka.http.scaladsl.server.Directive0
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import akka.util.ByteString
import sangria.ast.Document
import sangria.parser.QueryParser
import sangria.renderer.{QueryRenderer, QueryRendererConfig}

import scala.collection.immutable.Seq

object GraphQLRequestUnmarshaller {
  val `application/graphql` = MediaType.applicationWithFixedCharset("graphql", HttpCharsets.`UTF-8`, "graphql")

  def explicitlyAccepts(mediaType: MediaType): Directive0 =
    headerValuePF {
      case Accept(ranges) if ranges.exists(range ⇒ !range.isWildcard && range.matches(mediaType)) ⇒ ranges
    }.flatMap(_ ⇒ pass)

  def includeIf(include: Boolean): Directive0 =
    if (include) pass
    else reject

  def unmarshallerContentTypes: Seq[ContentTypeRange] =
    mediaTypes.map(ContentTypeRange.apply)

  def mediaTypes: Seq[MediaType.WithFixedCharset] =
    List(`application/graphql`)

  implicit final def documentMarshaller(implicit config: QueryRendererConfig = QueryRenderer.Compact): ToEntityMarshaller[Document] =
    Marshaller.oneOf(mediaTypes: _*) { mediaType ⇒
      Marshaller.withFixedContentType(ContentType(mediaType)) { json ⇒
        HttpEntity(mediaType, QueryRenderer.render(json, config))
      }
    }

  
  implicit final val documentUnmarshaller: FromEntityUnmarshaller[Document] =
    Unmarshaller.byteStringUnmarshaller
      .forContentTypes(unmarshallerContentTypes: _*)
      .map {
        case ByteString.empty ⇒ throw Unmarshaller.NoContentException
        case data ⇒
          import sangria.parser.DeliveryScheme.Throw

          QueryParser.parse(data.decodeString(Charset.forName("UTF-8")))
      }
} 
Example 12
Source File: SprayJsonSupport.scala    From mist   with Apache License 2.0 5 votes vote down vote up
package io.hydrosphere.mist.master.interfaces

import scala.language.implicitConversions
import akka.http.scaladsl.marshalling.{ ToEntityMarshaller, Marshaller }
import akka.http.scaladsl.unmarshalling.{ FromEntityUnmarshaller, Unmarshaller }
import akka.http.scaladsl.model.{ MediaTypes, HttpCharsets }

import spray.json._


trait SprayJsonSupport {
  implicit def sprayJsonUnmarshallerConverter[T](reader: RootJsonReader[T]): FromEntityUnmarshaller[T] =
    sprayJsonUnmarshaller(reader)
  implicit def sprayJsonUnmarshaller[T](implicit reader: RootJsonReader[T]): FromEntityUnmarshaller[T] =
    sprayJsValueUnmarshaller.map(jsonReader[T].read)
  implicit def sprayJsValueUnmarshaller: FromEntityUnmarshaller[JsValue] =
    Unmarshaller.byteStringUnmarshaller.mapWithCharset { (data, charset) ⇒
      val input =
        if (charset == HttpCharsets.`UTF-8`) ParserInput(data.toArray)
        else ParserInput(data.decodeString(charset.nioCharset.name)) // FIXME: identify charset by instance, not by name!
      JsonParser(input)
    }

  implicit def sprayJsonMarshallerConverter[T](writer: RootJsonWriter[T])(implicit printer: JsonPrinter = PrettyPrinter): ToEntityMarshaller[T] =
    sprayJsonMarshaller[T](writer, printer)
  implicit def sprayJsonMarshaller[T](implicit writer: RootJsonWriter[T], printer: JsonPrinter = PrettyPrinter): ToEntityMarshaller[T] =
    sprayJsValueMarshaller compose writer.write
  implicit def sprayJsValueMarshaller(implicit printer: JsonPrinter = PrettyPrinter): ToEntityMarshaller[JsValue] =
    Marshaller.StringMarshaller.wrap(MediaTypes.`application/json`)(printer)
}
object SprayJsonSupport extends SprayJsonSupport 
Example 13
Source File: HttpCodec.scala    From daml   with Apache License 2.0 5 votes vote down vote up
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package com.daml.http.json

import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
import akka.http.scaladsl.model.MediaTypes.`application/json`
import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.ExceptionHandler
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import com.daml.util.ExceptionOps._
import scalaz.std.stream.unfold
import scalaz.{@@, Tag}
import spray.json._

import scala.concurrent.{ExecutionContext, Future}


object HttpCodec {
  sealed trait JsonApi
  val JsonApi = Tag.of[JsonApi]

  implicit val jsonExceptionHandler: ExceptionHandler = ExceptionHandler {
    case e: DeserializationException =>
      complete(
        (
          StatusCodes.BadRequest,
          ResponseFormats.errorsJsObject(
            StatusCodes.BadRequest,
            s"JSON parser error: ${e.msg}" +: unfoldCauses(e.cause).map(_.description): _*)))
  }

  private[this] def unfoldCauses(t: Throwable): Seq[Throwable] =
    unfold(t)(tnq => Option(tnq) map (tnn => (tnn, tnn.getCause)))

  private[this] val simpleJsValueUnmarshaller =
    Unmarshaller[String, JsValue] { implicit ec: ExecutionContext => value =>
      Future(value.parseJson)
    }

  implicit val jsValueUnmarshaller: FromEntityUnmarshaller[JsValue] =
    (implicitly[FromEntityUnmarshaller[String]] andThen simpleJsValueUnmarshaller
      forContentTypes `application/json`)

  implicit val jsValueMarshaller: ToEntityMarshaller[JsValue] =
    Marshaller.combined((_: JsValue).compactPrint)(Marshaller.stringMarshaller(`application/json`))

  implicit def jsonCodecUnmarshaller[A: RootJsonReader]: FromEntityUnmarshaller[A @@ JsonApi] =
    JsonApi.subst[FromEntityUnmarshaller, A](jsValueUnmarshaller map (_.convertTo[A]))

  implicit def jsonCodecMarshaller[A: RootJsonWriter]: ToEntityMarshaller[A @@ JsonApi] =
    JsonApi.subst[ToEntityMarshaller, A](Marshaller.combined((_: A).toJson))
} 
Example 14
Source File: FlatBuffersSupport.scala    From ForestFlow   with Apache License 2.0 5 votes vote down vote up
package ai.forestflow.akka.flatbuffers

import java.nio.ByteBuffer

import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
import akka.http.scaladsl.model.{ContentTypeRange, MediaRange, MediaRanges, MediaType}
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import com.google.flatbuffers.Table

import scala.collection.mutable
import scala.reflect.ClassTag

// application/octet-stream
trait FlatBuffersSupport {
  var myMap : mutable.Map[ClassTag[_], AnyRef => AnyRef] = mutable.Map.empty[ClassTag[_], AnyRef => AnyRef]
  private val applicableMediaTypes: List[ContentTypeRange] = List(
    MediaRanges.`*

    Unmarshaller.byteArrayUnmarshaller.forContentTypes(applicableMediaTypes: _*).map(b => fn(java.nio.ByteBuffer.wrap(b)).asInstanceOf[T])
  }

  implicit def flatBufferBinaryMarshaller[T <: Table](implicit tag: ClassTag[T]): ToEntityMarshaller[T]  = {
    println("marshalling something")
    val result = Marshaller.ByteArrayMarshaller.compose((c: T) => c.getByteBuffer.array())
    println("done")
    result
  }
} 
Example 15
Source File: SealedOneofSupport.scala    From ForestFlow   with Apache License 2.0 5 votes vote down vote up
package ai.forestflow.scalapb

import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
import akka.http.scaladsl.model.{ContentTypeRange, MediaRanges, MediaType}
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import scalapb.GeneratedSealedOneof

import scala.reflect.ClassTag

// application/octet-stream
trait SealedOneofSupport {
  private val applicableMediaTypes: List[ContentTypeRange] = List(
    MediaRanges.`*/*`,
    MediaType.applicationBinary("octet-stream", MediaType.NotCompressible)
  )

  implicit def GeneratedSealedOneofBinaryUnmarshaller[T <: GeneratedSealedOneof]: FromEntityUnmarshaller[GeneratedSealedOneof]  = {
    Unmarshaller.byteArrayUnmarshaller.forContentTypes(applicableMediaTypes: _*).map(b =>  b.asInstanceOf[GeneratedSealedOneof].asMessage.companion.parseFrom(b).asInstanceOf[T])
  }

  implicit def GeneratedSealedOneofBinaryMarshaller[T <: GeneratedSealedOneof](implicit tag: ClassTag[T]): ToEntityMarshaller[T]  = {
    val result = Marshaller.ByteArrayMarshaller.compose((c: T) => c.asMessage.toByteArray)
    result
  }
} 
Example 16
Source File: IamIdentitiesClient.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.storage

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.client.RequestBuilding.Get
import akka.http.scaladsl.model.HttpRequest
import akka.http.scaladsl.model.headers.OAuth2BearerToken
import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller
import akka.util.ByteString
import cats.effect.{ContextShift, Effect, IO}
import cats.implicits._
import ch.epfl.bluebrain.nexus.rdf.implicits._
import ch.epfl.bluebrain.nexus.storage.IamIdentitiesClient.Identity._
import ch.epfl.bluebrain.nexus.storage.IamIdentitiesClient._
import ch.epfl.bluebrain.nexus.storage.IamIdentitiesClientError.IdentitiesSerializationError
import ch.epfl.bluebrain.nexus.storage.config.IamClientConfig
import de.heikoseeberger.akkahttpcirce.ErrorAccumulatingCirceSupport.{DecodingFailures => AccDecodingFailures}
import io.circe.Decoder.Result
import io.circe.{Decoder, DecodingFailure, HCursor}

import scala.concurrent.ExecutionContext

class IamIdentitiesClient[F[_]](config: IamClientConfig)(implicit F: Effect[F], as: ActorSystem)
    extends JsonLdCirceSupport {

  private val um: FromEntityUnmarshaller[Caller]      = unmarshaller[Caller]
  implicit private val ec: ExecutionContext           = as.dispatcher
  implicit private val contextShift: ContextShift[IO] = IO.contextShift(ec)

  def apply()(implicit credentials: Option[AccessToken]): F[Caller] =
    credentials match {
      case Some(token) => execute(Get(config.identitiesIri.asAkka).addCredentials(OAuth2BearerToken(token.value)))
      case None        => F.pure(Caller.anonymous)
    }

  private def execute(req: HttpRequest): F[Caller] = {
    IO.fromFuture(IO(Http().singleRequest(req))).to[F].flatMap { resp =>
      if (resp.status.isSuccess())
        IO.fromFuture(IO(um(resp.entity))).to[F].recoverWith {
          case err: AccDecodingFailures => F.raiseError(IdentitiesSerializationError(err.getMessage))
          case err: Error               => F.raiseError(IdentitiesSerializationError(err.getMessage))
        }
      else
        IO.fromFuture(IO(resp.entity.dataBytes.runFold(ByteString(""))(_ ++ _).map(_.utf8String)))
          .to[F]
          .flatMap { err => F.raiseError(IamIdentitiesClientError.unsafe(resp.status, err)) }
    }
  }

}

object IamIdentitiesClient {

  
    final case class Authenticated(realm: String) extends Identity

    private def decodeAnonymous(hc: HCursor): Result[Subject] =
      hc.get[String]("@type").flatMap {
        case "Anonymous" => Right(Anonymous)
        case _           => Left(DecodingFailure("Cannot decode Anonymous Identity", hc.history))
      }

    private def decodeUser(hc: HCursor): Result[Subject] =
      (hc.get[String]("subject"), hc.get[String]("realm")).mapN {
        case (subject, realm) => User(subject, realm)
      }

    private def decodeGroup(hc: HCursor): Result[Identity] =
      (hc.get[String]("group"), hc.get[String]("realm")).mapN {
        case (group, realm) => Group(group, realm)
      }

    private def decodeAuthenticated(hc: HCursor): Result[Identity] =
      hc.get[String]("realm").map(Authenticated)

    private val attempts =
      List[HCursor => Result[Identity]](decodeAnonymous, decodeUser, decodeGroup, decodeAuthenticated)

    implicit val identityDecoder: Decoder[Identity] =
      Decoder.instance { hc =>
        attempts.foldLeft(Left(DecodingFailure("Unexpected", hc.history)): Result[Identity]) {
          case (acc @ Right(_), _) => acc
          case (_, f)              => f(hc)
        }
      }
  }

} 
Example 17
Source File: PhoneBookWebService.scala    From udash-demos   with GNU General Public License v3.0 5 votes vote down vote up
package io.udash.demos.rest.api

import akka.http.scaladsl.marshalling._
import akka.http.scaladsl.model.{HttpEntity, MediaTypes, StatusCodes}
import com.avsystem.commons.serialization.GenCodec
import io.udash.demos.rest.model._
import io.udash.demos.rest.services.{ContactService, InMemoryContactService, InMemoryPhoneBookService, PhoneBookService}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.{RequestContext, Route}
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import com.avsystem.commons.serialization.json.{JsonStringInput, JsonStringOutput}


trait PhoneBookWebServiceSpec {
  private val staticsDir = "frontend/target/UdashStatics/WebContent"

  val phoneBookService: PhoneBookService
  val contactService: ContactService

  implicit def optionMarshaller[T](implicit codec: GenCodec[T]): ToResponseMarshaller[Option[T]] =
    gencodecMarshaller[Option[T]](GenCodec.optionCodec(codec))

  implicit def gencodecMarshaller[T](implicit codec: GenCodec[T]): ToEntityMarshaller[T] =
    Marshaller.withFixedContentType(MediaTypes.`application/json`) { value =>
      HttpEntity(MediaTypes.`application/json`, JsonStringOutput.write(value))
    }

  implicit def gencodecUnmarshaller[T](implicit codec: GenCodec[T]): FromEntityUnmarshaller[T] =
    Unmarshaller.stringUnmarshaller.forContentTypes(MediaTypes.`application/json`).map{ data =>
      JsonStringInput.read[T](data)
    }

  private def completeIfNonEmpty[T](ctx: RequestContext)(opt: Option[T])(implicit rm: ToResponseMarshaller[T]) =
    opt match {
      case Some(v) => complete(v)(ctx)
      case None => complete(StatusCodes.NotFound)(ctx)
    }

  val route: Route = {
    pathPrefix("scripts"){
      getFromDirectory(s"$staticsDir/scripts")
    } ~
    pathPrefix("assets"){
      getFromDirectory(s"$staticsDir/assets")
    } ~
    pathPrefix("api") {
      pathPrefix("book") {
        pathPrefix(Segment) { segment =>
          val bookId = PhoneBookId(segment.toInt)
          pathPrefix("contacts") {
            pathPrefix("count") {
              get {
                
            entity(as[Contact]) { contact =>
              complete { contactService.create(contact) }
            }
          }
      }
    } ~ get {
      getFromFile(s"$staticsDir/index.html")
    }
  }
}

class PhoneBookWebService() extends PhoneBookWebServiceSpec {
  override val phoneBookService: PhoneBookService = InMemoryPhoneBookService
  override val contactService: ContactService = InMemoryContactService
} 
Example 18
Source File: AkkaHttpMarshalling.scala    From telegram   with Apache License 2.0 5 votes vote down vote up
package com.bot4s.telegram.marshalling

import akka.http.scaladsl.marshalling.{Marshaller, Marshalling, ToEntityMarshaller}
import akka.http.scaladsl.model._
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import com.bot4s.telegram.marshalling
import com.bot4s.telegram.methods.{JsonRequest, MultipartRequest, Request}
import com.bot4s.telegram.models.{AkkaInputFile, InputFile}
import io.circe.{Decoder, Encoder}


object AkkaHttpMarshalling {

  implicit def camelCaseJsonUnmarshaller[R](implicit decR: Decoder[R]): FromEntityUnmarshaller[R] = {
    Unmarshaller
      .stringUnmarshaller
      .forContentTypes(ContentTypes.`application/json`)
      .map(marshalling.fromJson[R])
  }

  implicit def underscore_case_marshaller[T <: Request[_]](implicit encT: Encoder[T]): ToEntityMarshaller[T] = {
    Marshaller.strict {
      request => request match {
        // JSON-only request
        case r: JsonRequest[_] =>
          Marshalling.Opaque(() => HttpEntity(ContentTypes.`application/json`, marshalling.toJson(request)))

        // Request with multipart payload
        case r: MultipartRequest[_] =>
          val files = r.getFiles
          val parts = files.map {
            case (camelKey, inputFile) =>
              val key = CaseConversions.snakenize(camelKey)
              inputFile match {
                case InputFile.FileId(id) => Multipart.FormData.BodyPart(key, HttpEntity(id))

                case InputFile.Contents(filename, contents) =>
                  Multipart.FormData.BodyPart(key, HttpEntity(ContentTypes.`application/octet-stream`, contents),
                    Map("filename" -> filename))

                case InputFile.Path(path) =>
                  Multipart.FormData.BodyPart.fromPath(key, MediaTypes.`application/octet-stream`, path)

                case AkkaInputFile.ByteString(filename, bytes) =>
                  Multipart.FormData.BodyPart(key, HttpEntity(MediaTypes.`application/octet-stream`, bytes),
                    Map("filename" -> filename))

                case other =>
                  throw new RuntimeException(s"InputFile $other not supported")
              }
          }

          val fields = io.circe.parser.parse(marshalling.toJson(request)).fold(throw _, _.asObject.map {
            _.toMap.mapValues {
              json =>
                json.asString.getOrElse(marshalling.printer.pretty(json))
            }
          })

          val params = fields.getOrElse(Map())
          val paramParts = params.map { case (key, value) => Multipart.FormData.BodyPart(key, HttpEntity(value)) }

          Marshalling.Opaque(() => Multipart.FormData((parts ++ paramParts): _*).toEntity())
      }
    }
  }
} 
Example 19
Source File: AkkaHttpCirceSupport.scala    From scalanda-v20   with MIT License 5 votes vote down vote up
package com.msilb.scalandav20.common

import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
import akka.http.scaladsl.model.MediaTypes.`application/json`
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import akka.util.ByteString
import io.circe._

object AkkaHttpCirceSupport extends AkkaHttpCirceSupport

trait AkkaHttpCirceSupport {

  private val jsonStringUnmarshaller =
    Unmarshaller.byteStringUnmarshaller
      .forContentTypes(`application/json`)
      .mapWithCharset {
        case (ByteString.empty, _) => throw Unmarshaller.NoContentException
        case (data, charset) => data.decodeString(charset.nioCharset.name)
      }

  private val jsonStringMarshaller = Marshaller.stringMarshaller(`application/json`)

  implicit def circeUnmarshaller[A](implicit decoder: Decoder[A]): FromEntityUnmarshaller[A] =
    jsonStringUnmarshaller.map(jawn.decode(_).fold(throw _, identity))

  implicit def circeToEntityMarshaller[A](implicit encoder: Encoder[A],
                                          printer: Json => String = Printer.noSpaces.copy(dropNullValues = true).pretty): ToEntityMarshaller[A] =
    jsonStringMarshaller.compose(printer).compose(encoder.apply)
} 
Example 20
Source File: JsonUnmarshaller.scala    From akka-http-oauth2-client   with Apache License 2.0 5 votes vote down vote up
package com.github.dakatsuka.akka.http.oauth2.client.utils

import akka.http.scaladsl.model.ContentTypeRange
import akka.http.scaladsl.model.MediaTypes.`application/json`
import akka.http.scaladsl.unmarshalling.{ FromEntityUnmarshaller, Unmarshaller }
import akka.util.ByteString
import io.circe.{ jawn, Decoder, Json }

trait JsonUnmarshaller {
  def unmarshallerContentTypes: Seq[ContentTypeRange] =
    List(`application/json`)

  implicit def jsonUnmarshaller: FromEntityUnmarshaller[Json] =
    Unmarshaller.byteStringUnmarshaller
      .forContentTypes(unmarshallerContentTypes: _*)
      .map {
        case ByteString.empty => throw Unmarshaller.NoContentException
        case data             => jawn.parseByteBuffer(data.asByteBuffer).fold(throw _, identity)
      }

  implicit def unmarshaller[A: Decoder]: FromEntityUnmarshaller[A] = {
    def decode(json: Json) = implicitly[Decoder[A]].decodeJson(json).fold(throw _, identity)
    jsonUnmarshaller.map(decode)
  }
} 
Example 21
Source File: ApiMarshallers.scala    From matcher   with MIT License 5 votes vote down vote up
package com.wavesplatform.dex.api.http

import akka.http.scaladsl.marshalling.{Marshaller, PredefinedToEntityMarshallers, ToEntityMarshaller}
import akka.http.scaladsl.model.MediaTypes.{`application/json`, `text/plain`}
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, PredefinedFromEntityUnmarshallers, Unmarshaller}
import akka.util.ByteString
import com.wavesplatform.dex.api.http.json.CustomJson
import com.wavesplatform.dex.domain.transaction.ExchangeTransaction
import play.api.libs.json._

import scala.util.control.Exception.nonFatalCatch
import scala.util.control.NoStackTrace

case class PlayJsonException(cause: Option[Throwable] = None, errors: Seq[(JsPath, Seq[JsonValidationError])] = Seq.empty)
    extends IllegalArgumentException(s"JSON parsing errors:\n${errors.mkString("\n")}", cause.orNull)
    with NoStackTrace

trait ApiMarshallers {

  implicit lazy val ExchangeTransactionJsonWrites: Writes[ExchangeTransaction] = Writes(_.json())

  private[this] lazy val jsonStringUnmarshaller =
    Unmarshaller.byteStringUnmarshaller
      .forContentTypes(`application/json`)
      .mapWithCharset {
        case (ByteString.empty, _) => throw Unmarshaller.NoContentException
        case (data, charset)       => data.decodeString(charset.nioCharset.name)
      }

  private[this] lazy val jsonStringMarshaller = Marshaller.stringMarshaller(`application/json`)

  private[this] lazy val customJsonStringMarshaller = Marshaller.stringMarshaller(CustomJson.jsonWithNumbersAsStrings)

  implicit def playJsonUnmarshaller[A](implicit reads: Reads[A]): FromEntityUnmarshaller[A] =
    jsonStringUnmarshaller.map { data =>
      val json = nonFatalCatch.withApply(t => throw PlayJsonException(cause = Some(t)))(Json.parse(data))

      json.validate[A] match {
        case JsSuccess(value, _) => value
        case JsError(errors)     => throw PlayJsonException(errors = errors)
      }
    }

  // preserve support for extracting plain strings from requests
  implicit val stringUnmarshaller: FromEntityUnmarshaller[String] = PredefinedFromEntityUnmarshallers.stringUnmarshaller
  implicit val intUnmarshaller: FromEntityUnmarshaller[Int]       = stringUnmarshaller.map(_.toInt)

  implicit def playJsonMarshaller[A](implicit writes: Writes[A], jsValueToString: JsValue => String = Json.stringify): ToEntityMarshaller[A] =
    Marshaller.oneOf(
      jsonStringMarshaller
        .compose(jsValueToString)
        .compose(writes.writes),
      customJsonStringMarshaller
        .compose(CustomJson.writeValueAsString)
        .compose(writes.writes)
    )

  // preserve support for using plain strings as request entities
  implicit val stringMarshaller = PredefinedToEntityMarshallers.stringMarshaller(`text/plain`)
}

object ApiMarshallers extends ApiMarshallers 
Example 22
Source File: SangriaGraphQLSupport.scala    From incubator-s2graph   with Apache License 2.0 5 votes vote down vote up
package org.apache.s2graph.http

import java.nio.charset.Charset

import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
import akka.http.scaladsl.model._
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import akka.util.ByteString
import sangria.ast.Document
import sangria.parser.QueryParser
import sangria.renderer.{QueryRenderer, QueryRendererConfig}

trait SangriaGraphQLSupport {
  private val mediaTypes: Seq[MediaType.WithFixedCharset] =
    Seq(MediaType.applicationWithFixedCharset("graphql", HttpCharsets.`UTF-8`, "graphql"))

  private val unmarshallerContentTypes: Seq[ContentTypeRange] = mediaTypes.map(ContentTypeRange.apply)

  implicit def documentMarshaller(implicit config: QueryRendererConfig = QueryRenderer.Compact): ToEntityMarshaller[Document] = {
    Marshaller.oneOf(mediaTypes: _*) {
      mediaType ⇒
        Marshaller.withFixedContentType(ContentType(mediaType)) {
          json ⇒ HttpEntity(mediaType, QueryRenderer.render(json, config))
        }
    }
  }

  implicit val documentUnmarshaller: FromEntityUnmarshaller[Document] = {
    Unmarshaller.byteStringUnmarshaller
      .forContentTypes(unmarshallerContentTypes: _*)
      .map {
        case ByteString.empty ⇒ throw Unmarshaller.NoContentException
        case data ⇒
          import sangria.parser.DeliveryScheme.Throw
          QueryParser.parse(data.decodeString(Charset.forName("UTF-8")))
      }
  }
} 
Example 23
Source File: PlayJsonSupport.scala    From incubator-s2graph   with Apache License 2.0 5 votes vote down vote up
package org.apache.s2graph.http

import java.nio.charset.Charset

import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
import akka.http.scaladsl.model._
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import akka.util.ByteString
import play.api.libs.json._

trait PlayJsonSupport {

  private val mediaTypes: Seq[MediaType.WithFixedCharset] =
    Seq(MediaType.applicationWithFixedCharset("json", HttpCharsets.`UTF-8`, "js"))

  private val unmarshallerContentTypes: Seq[ContentTypeRange] = mediaTypes.map(ContentTypeRange.apply)

  implicit val playJsonMarshaller: ToEntityMarshaller[JsValue] = {
    Marshaller.oneOf(mediaTypes: _*) { mediaType =>
      Marshaller.withFixedContentType(ContentType(mediaType)) {
        json => HttpEntity(mediaType, json.toString)
      }
    }
  }

  implicit val playJsonUnmarshaller: FromEntityUnmarshaller[JsValue] = {
    Unmarshaller.byteStringUnmarshaller
      .forContentTypes(unmarshallerContentTypes: _*)
      .map {
        case ByteString.empty => throw Unmarshaller.NoContentException
        case data => Json.parse(data.decodeString(Charset.forName("UTF-8")))
      }
  }

  trait ToPlayJson[T] {
    def toJson(msg: T): JsValue
  }

  import scala.language.reflectiveCalls

  object ToPlayJson {
    type ToPlayJsonReflective = {
      def toJson: JsValue
    }

    implicit def forToJson[A <: ToPlayJsonReflective] = new ToPlayJson[A] {
      def toJson(js: A) = js.toJson
    }

    implicit def forPlayJson[A <: JsValue] = new ToPlayJson[A] {
      def toJson(js: A) = js
    }
  }

  implicit object JsErrorJsonWriter extends Writes[JsError] {
    def writes(o: JsError): JsValue = Json.obj(
      "errors" -> JsArray(
        o.errors.map {
          case (path, validationErrors) => Json.obj(
            "path" -> Json.toJson(path.toString()),
            "validationErrors" -> JsArray(validationErrors.map(validationError => Json.obj(
              "message" -> JsString(validationError.message),
              "args" -> JsArray(validationError.args.map {
                case x: Int => JsNumber(x)
                case x => JsString(x.toString)
              })
            )))
          )
        }
      )
    )
  }

}