org.http4s.EntityDecoder Scala Examples

The following examples show how to use org.http4s.EntityDecoder. 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: PriceRoutes.scala    From http4s-poc-api   with MIT License 5 votes vote down vote up
package server

import cats.effect.Sync
import cats.syntax.applicativeError._
import cats.syntax.flatMap._
import cats.syntax.functor._
import cats.syntax.show._
import errors.PriceServiceError
import errors.PriceServiceError._
import external.library.syntax.response._
import model.DomainModel._
import org.http4s.dsl.Http4sDsl
import org.http4s.{EntityDecoder, EntityEncoder, HttpRoutes, Method, Request, Response}
import service.PriceService

sealed abstract class PriceRoutes[F[_]: Sync](
  implicit requestDecoder: EntityDecoder[F, PricesRequestPayload],
  responseEncoder: EntityEncoder[F, List[Price]]
) extends Http4sDsl[F] {
  def make(priceService: PriceService[F]): HttpRoutes[F] =
    HttpRoutes.of[F] {
      case req @ Method.POST -> Root =>
        postResponse(req, priceService) handlingFailures priceServiceErrors handleErrorWith unhandledThrowable
    }

  private[this] def postResponse(request: Request[F], priceService: PriceService[F]): F[Response[F]] =
    for {
      payload <- request.as[PricesRequestPayload]
      prices  <- priceService.prices(payload.userId, payload.productIds)
      resp    <- Ok(prices)
    } yield resp

  private[this] def priceServiceErrors: PriceServiceError => F[Response[F]] = {
    case UserErr(r)                => FailedDependency(r)
    case PreferenceErr(r)          => FailedDependency(r)
    case ProductErr(r)             => FailedDependency(r)
    case ProductPriceErr(r)        => FailedDependency(r)
    case CacheLookupError(r)       => FailedDependency(r)
    case CacheStoreError(r)        => FailedDependency(r)
    case InvalidShippingCountry(r) => BadRequest(r)
  }

  private[this] def unhandledThrowable: Throwable => F[Response[F]] = { th =>
    import external.library.instances.throwable._
    InternalServerError(th.show)
  }
}

object PriceRoutes {
  def apply[
    F[_]: Sync: EntityDecoder[*[_], PricesRequestPayload]: EntityEncoder[*[_], List[Price]]
  ]: PriceRoutes[F] =
    new PriceRoutes[F] {}
} 
Example 2
Source File: ResponseContent.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.core

import cats.data.NonEmptyList
import cats.effect.{Effect, Sync}
import io.circe.Json
import org.http4s.{EntityDecoder, MediaRange, Message}
import org.http4s.scalaxml._
import org.http4s.circe._

private[aws4s] sealed trait ResponseContent {
  final def tryParse[A](pf: PartialFunction[ResponseContent, Option[A]]): Option[A] =
    pf.orElse[ResponseContent, Option[A]]({ case _ => None })(this)
}

private[aws4s] case class XmlContent(elem:    scala.xml.Elem) extends ResponseContent
private[aws4s] case class JsonContent(json:   Json) extends ResponseContent
private[aws4s] case class StringContent(text: String) extends ResponseContent
private[aws4s] case object NoContent extends ResponseContent

private[aws4s] object ResponseContent {

  implicit def entityDecoder[F[_]: Effect]: EntityDecoder[F, ResponseContent] =
    EntityDecoder[F, scala.xml.Elem].map(elem => XmlContent(elem)).widen[ResponseContent] orElse
      EntityDecoder[F, Json].map(json         => JsonContent(json)).widen[ResponseContent] orElse
      inclusiveJsonEntityDecoder.map(json     => JsonContent(json)).widen[ResponseContent] orElse
      EntityDecoder[F, String].map(text       => StringContent(text)).widen[ResponseContent] orElse
      EntityDecoder[F, Unit].map(_            => NoContent).widen[ResponseContent]

  private def inclusiveJsonEntityDecoder[F[_]: Sync]: EntityDecoder[F, Json] = {
    val json = jsonDecoder[F]
    val extraMediaRanges = NonEmptyList.of(
      "application/x-amz-json-1.0"
    ) map (mr => MediaRange.parse(mr).getOrElse(throw new RuntimeException(s"Invalid Media Range: $mr")))
    val allMediaRanges = extraMediaRanges concat json.consumes.toList
    EntityDecoder.decodeBy[F, Json](allMediaRanges.head, allMediaRanges.tail: _*)((msg: Message[F]) => json.decode(msg, strict = false))
  }
} 
Example 3
Source File: ExtraEntityDecoderInstances.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.core

import cats.Applicative
import cats.data.EitherT
import cats.effect.Effect
import cats.implicits._
import fs2.Stream
import io.circe.Decoder
import org.http4s.scalaxml._
import org.http4s.{DecodeFailure, EntityDecoder, InvalidMessageBodyFailure, MediaRange}

private[aws4s] object ExtraEntityDecoderInstances {
  implicit def streamEntityDecoder[F[_]: Applicative]: EntityDecoder[F, Stream[F, Byte]] =
    EntityDecoder.decodeBy(MediaRange.`*/*`) { msg =>
      EitherT.fromEither(msg.body.asRight[DecodeFailure])
    }

  def fromXml[F[_]: Effect, A](f: scala.xml.Elem => Option[A]): EntityDecoder[F, A] =
    EntityDecoder[F, scala.xml.Elem] flatMapR { elem =>
      val result = f(elem)
      EitherT.fromEither(result.toRight(InvalidMessageBodyFailure("Response was not as expected")))
    }

  implicit def circeEntityDecoder[F[_]: Effect, A: Decoder]: EntityDecoder[F, A] =
    org.http4s.circe.jsonOf[F, A]
} 
Example 4
Source File: ListBuckets.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.s3

import cats.effect.Effect
import org.aws4s._
import org.http4s.{EntityDecoder, Method}
import cats.implicits._
import fs2.Stream
import org.aws4s.core.ExtraEntityDecoderInstances

private[s3] case class ListBuckets[F[_]: Effect](
    region: Region
) extends S3ServiceCommand[F, ListBucketsSuccess] {

  override val action:  Method             = Method.GET
  override val payload: F[Stream[F, Byte]] = (Stream.empty: Stream[F, Byte]).pure[F]
}

case class ListBucketsSuccess(
    buckets: List[BucketName]
)

object ListBucketsSuccess {
  implicit def entityDecoder[F[_]: Effect]: EntityDecoder[F, ListBucketsSuccess] =
    ExtraEntityDecoderInstances.fromXml { elem =>
      if (elem.label == "ListAllMyBucketsResult")
        (elem \ "Buckets" \ "Bucket").toList.traverse(BucketName.parse) map { buckets =>
          ListBucketsSuccess(buckets)
        } else None
    }
} 
Example 5
Source File: S3ServiceCommand.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.s3

import cats.effect.Effect
import cats.implicits._
import fs2._
import org.aws4s.PayloadSigning
import org.aws4s.core.{Command, Param, RenderedParam, ServiceName}
import org.http4s.headers.Host
import org.http4s.{EntityDecoder, Headers, Method, Request, Uri}

private[aws4s] abstract class S3ServiceCommand[F[_]: Effect, R: EntityDecoder[F, ?]] extends Command[F, Nothing, R] {

  override final val serviceName: ServiceName = ServiceName.S3

  val action:  Method
  val payload: F[Stream[F, Byte]]

  override final val payloadSigning: PayloadSigning              = PayloadSigning.Signed
  override final val params:         List[Param[Nothing]]       = List.empty
  override final val validator:      Command.Validator[Nothing] = _ => None

  override final val requestGenerator: List[RenderedParam[Nothing]] => F[Request[F]] = { _ =>
    val host = s"s3.${region.name}.amazonaws.com"
    val uri  = Uri.unsafeFromString(s"https://$host/").withPath("/")
    payload map { p =>
      Request[F](action, uri, headers = Headers(Host(host))).withBodyStream(p)
    }
  }
} 
Example 6
Source File: S3ObjectCommand.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.s3

import cats.effect.Effect
import org.aws4s.core.{Command, Param, RenderedParam, ServiceName}
import org.http4s.{EntityDecoder, Headers, Method, Request, Uri}
import fs2._
import org.http4s.headers.Host
import cats.implicits._

private[aws4s] abstract class S3ObjectCommand[F[_]: Effect, R: EntityDecoder[F, ?]] extends Command[F, Nothing, R] {

  override final val serviceName: ServiceName = ServiceName.S3

  val action:     Method
  val bucketName: BucketName
  val objectPath: ObjectPath
  val payload:    F[Stream[F, Byte]]

  override final val params:    List[Param[Nothing]]       = List.empty
  override final val validator: Command.Validator[Nothing] = _ => None

  override final val requestGenerator: List[RenderedParam[Nothing]] => F[Request[F]] = { _ =>
    val host = s"${bucketName.value}.s3.${region.name}.amazonaws.com"
    val uri  = Uri.unsafeFromString(s"https://$host/").withPath(objectPath.value)
    for {
      pStream <- payload
      pBytes <- pStream.compile.toVector
      r <- Request[F](action, uri, headers = Headers(Host(host))).withBody(pBytes.toArray)
    } yield r
  }
} 
Example 7
Source File: SendMessage.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.sqs

import cats.effect.Effect
import org.http4s.EntityDecoder
import org.aws4s.core.XmlParsing._
import org.aws4s.core.{CommandPayload, ExtraEntityDecoderInstances, Param}

private[sqs] case class SendMessage[F[_]: Effect](
    q:                      Queue,
    messageBody:            MessageBody,
    delaySeconds:           Option[DelaySeconds] = None,
    messageDeduplicationId: Option[MessageDeduplicationId] = None,
) extends SqsCommand[F, SendMessageSuccess] {

  override val action: String = "SendMessage"

  override def params: List[Param[String]] =
    CommandPayload.params(
      messageBody
    )(
      delaySeconds,
      messageDeduplicationId
    )
}

case class SendMessageSuccess(
    messageId:        MessageId,
    md5OfMessageBody: String,
    sequenceNumber:   Option[SequenceNumber]
)

object SendMessageSuccess {
  implicit def entityDecoder[F[_]: Effect]: EntityDecoder[F, SendMessageSuccess] =
    ExtraEntityDecoderInstances.fromXml { elem =>
      if (elem.label == "SendMessageResponse")
        Some(
          SendMessageSuccess(
            MessageId(text(elem)("SendMessageResult", "MessageId")),
            text(elem)("SendMessageResult", "MD5OfMessageBody"),
            integer(elem)("SendMessageResult", "SequenceNumber") map SequenceNumber
          )
        )
      else
        None
    }
} 
Example 8
Source File: SqsCommand.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.sqs

import cats.effect.Effect
import org.http4s.headers.Host
import org.http4s.{EntityDecoder, Headers, Method, Request, UrlForm}
import org.aws4s._
import org.aws4s.core.Command.Validator
import org.aws4s.core.{Command, RenderedParam, ServiceName}

private[sqs] abstract class SqsCommand[F[_]: Effect, R: EntityDecoder[F, ?]] extends Command[F, String, R] {

  val q:      Queue
  val action: String

  override final val serviceName:    ServiceName    = ServiceName.Sqs
  override final val payloadSigning: PayloadSigning = PayloadSigning.Signed
  override final val region: Region = q.region

  override final val validator: Validator[String] = _ => None
  override final val requestGenerator: List[RenderedParam[String]] => F[Request[F]] = { params =>
    val body = params.map(p => (p.name, p.value)).foldLeft(UrlForm())((form, newPair) => form + newPair) + ("Action" -> action)
    Request[F](Method.POST, q.uri, headers = Headers(Host(q.host))).withBody[UrlForm](body)
  }
} 
Example 9
Source File: ReceiveMessage.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.sqs

import cats.effect.Effect
import org.http4s.EntityDecoder
import cats.implicits._
import org.aws4s.core.{CommandPayload, ExtraEntityDecoderInstances, Param}

private[sqs] case class ReceiveMessage[F[_]: Effect](
    q:                       Queue,
    maxNumberOfMessages:     Option[MaxNumberOfMessages],
    visibilityTimeout:       Option[VisibilityTimeout],
    waitTimeSeconds:         Option[WaitTimeSeconds],
    receiveRequestAttemptId: Option[ReceiveRequestAttemptId],
) extends SqsCommand[F, ReceiveMessageSuccess] {

  override val action: String = "ReceiveMessage"

  override final val params: List[Param[String]] =
    CommandPayload.params()(
      maxNumberOfMessages,
      visibilityTimeout,
      waitTimeSeconds,
      receiveRequestAttemptId
    )
}

case class ReceiveMessageSuccess(
    messages: List[Message]
)

object ReceiveMessageSuccess {
  implicit def entityDecoder[F[_]: Effect]: EntityDecoder[F, ReceiveMessageSuccess] =
    ExtraEntityDecoderInstances.fromXml { elem =>
      if (elem.label == "ReceiveMessageResponse")
        (elem \ "ReceiveMessageResult" \ "Message").toList.traverse(Message.parse) map { messages =>
          ReceiveMessageSuccess(messages)
        } else None
    }
} 
Example 10
Source File: InvoicesApi.scala    From event-sourcing-kafka-streams   with MIT License 5 votes vote down vote up
package org.amitayh.invoices.web

import java.util.UUID

import cats.effect.{Concurrent, Timer}
import cats.implicits._
import fs2.Stream
import fs2.concurrent.Topic
import io.circe._
import io.circe.generic.auto._
import io.circe.syntax._
import org.amitayh.invoices.common.domain.CommandResult.{Failure, Success}
import org.amitayh.invoices.common.domain.{Command, CommandResult}
import org.amitayh.invoices.dao.InvoiceList
import org.amitayh.invoices.web.CommandDto._
import org.amitayh.invoices.web.PushEvents.CommandResultRecord
import org.http4s.circe._
import org.http4s.dsl.Http4sDsl
import org.http4s.{EntityDecoder, HttpRoutes, Response}

import scala.concurrent.duration._

class InvoicesApi[F[_]: Concurrent: Timer] extends Http4sDsl[F] {

  private val maxQueued = 16

  implicit val commandEntityDecoder: EntityDecoder[F, Command] = jsonOf[F, Command]

  def service(invoiceList: InvoiceList[F],
              producer: Kafka.Producer[F, UUID, Command],
              commandResultsTopic: Topic[F, CommandResultRecord]): HttpRoutes[F] = HttpRoutes.of[F] {
    case GET -> Root / "invoices" =>
      invoiceList.get.flatMap(invoices => Ok(invoices.asJson))

    case request @ POST -> Root / "execute" / "async" / UuidVar(invoiceId) =>
      request
        .as[Command]
        .flatMap(producer.send(invoiceId, _))
        .flatMap(metaData => Accepted(Json.fromLong(metaData.timestamp)))

    case request @ POST -> Root / "execute" / UuidVar(invoiceId) =>
      request.as[Command].flatMap { command =>
        val response = resultStream(commandResultsTopic, command.commandId) merge timeoutStream
        producer.send(invoiceId, command) *> response.head.compile.toList.map(_.head)
      }
  }

  private def resultStream(commandResultsTopic: Topic[F, CommandResultRecord],
                           commandId: UUID): Stream[F, Response[F]] =
    commandResultsTopic.subscribe(maxQueued).collectFirst {
      case Some((_, CommandResult(_, `commandId`, outcome))) => outcome
    }.flatMap {
      case Success(_, _, snapshot) => Stream.eval(Ok(snapshot.asJson))
      case Failure(cause) => Stream.eval(UnprocessableEntity(cause.message))
    }

  private def timeoutStream: Stream[F, Response[F]] =
    Stream.eval(Timer[F].sleep(5.seconds) *> RequestTimeout("timeout"))

}

object InvoicesApi {
  def apply[F[_]: Concurrent: Timer]: InvoicesApi[F] = new InvoicesApi[F]
} 
Example 11
Source File: Http4sRequestToRawBody.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.server.http4s

import java.io.ByteArrayInputStream

import cats.effect.{Blocker, ContextShift, Sync}
import cats.implicits._
import fs2.Chunk
import org.http4s.headers.{`Content-Disposition`, `Content-Type`}
import org.http4s.{Charset, EntityDecoder, Request, multipart}
import sttp.model.{Header, Part}
import sttp.tapir.{RawPart, RawBodyType}

class Http4sRequestToRawBody[F[_]: Sync: ContextShift](serverOptions: Http4sServerOptions[F]) {
  def apply[R](body: fs2.Stream[F, Byte], bodyType: RawBodyType[R], charset: Option[Charset], req: Request[F]): F[R] = {
    def asChunk: F[Chunk[Byte]] = body.compile.to(Chunk)
    def asByteArray: F[Array[Byte]] = body.compile.to(Chunk).map(_.toByteBuffer.array())

    bodyType match {
      case RawBodyType.StringBody(defaultCharset) => asByteArray.map(new String(_, charset.map(_.nioCharset).getOrElse(defaultCharset)))
      case RawBodyType.ByteArrayBody              => asByteArray
      case RawBodyType.ByteBufferBody             => asChunk.map(_.toByteBuffer)
      case RawBodyType.InputStreamBody            => asByteArray.map(new ByteArrayInputStream(_))
      case RawBodyType.FileBody =>
        serverOptions.createFile(serverOptions.blockingExecutionContext, req).flatMap { file =>
          val fileSink = fs2.io.file.writeAll(file.toPath, Blocker.liftExecutionContext(serverOptions.blockingExecutionContext))
          body.through(fileSink).compile.drain.map(_ => file)
        }
      case m: RawBodyType.MultipartBody =>
        // TODO: use MultipartDecoder.mixedMultipart once available?
        implicitly[EntityDecoder[F, multipart.Multipart[F]]].decode(req, strict = false).value.flatMap {
          case Left(failure) =>
            throw new IllegalArgumentException("Cannot decode multipart body: " + failure) // TODO
          case Right(mp) =>
            val rawPartsF: Vector[F[RawPart]] = mp.parts
              .flatMap(part => part.name.flatMap(name => m.partType(name)).map((part, _)).toList)
              .map { case (part, codecMeta) => toRawPart(part, codecMeta, req).asInstanceOf[F[RawPart]] }

            val rawParts: F[Vector[RawPart]] = rawPartsF.sequence

            rawParts.asInstanceOf[F[R]] // R is Seq[RawPart]
        }
    }
  }

  private def toRawPart[R](part: multipart.Part[F], partType: RawBodyType[R], req: Request[F]): F[Part[R]] = {
    val dispositionParams = part.headers.get(`Content-Disposition`).map(_.parameters).getOrElse(Map.empty)
    val charset = part.headers.get(`Content-Type`).flatMap(_.charset)
    apply(part.body, partType, charset, req)
      .map(r =>
        Part(
          part.name.getOrElse(""),
          r,
          otherDispositionParams = dispositionParams - Part.NameDispositionParam,
          headers = part.headers.toList.map(h => Header(h.name.value, h.value))
        )
      )
  }
} 
Example 12
Source File: ResponseVerificationSyntax.scala    From http4s-poc-api   with MIT License 5 votes vote down vote up
package syntax

import java.nio.charset.StandardCharsets

import cats.data.Validated
import cats.instances.string._
import cats.syntax.eq._
import cats.syntax.show._
import cats.syntax.validated._
import cats.{Eq, Show}
import org.http4s.{EntityDecoder, Response, Status}
import typeclasses.RunSync
import zio.Task
import zio.interop.catz._

import scala.language.implicitConversions

private[syntax] trait ResponseVerificationSyntax {
  implicit def verifiedSyntax[A](a: A): VerifiedOps[A]                     = new VerifiedOps(a)
  implicit def verifiedOptionSyntax[A](a: Option[A]): VerifiedOptionOps[A] = new VerifiedOptionOps(a)

  implicit def responseVerificationSyntax(response: Task[Response[Task]]) =
    new IoResponseResultOps(response)
}

private[syntax] class IoResponseResultOps(private val response: Task[Response[Task]]) extends AnyVal {
  import syntax.responseVerification._

  def verify[A: EntityDecoder[Task, *]](status: Status, check: A => Verified[A])(
    implicit ev1: Eq[Status],
    ev2: Show[Status],
    run: RunSync[Task]
  ): Verified[A] =
    run
      .syncUnsafe(response)
      .fold(
        err => s"Should succeed but returned the error $err".invalidNel,
        res => res.status isSameAs status andThen { _ => verifiedResponse[A](res, check) }
      )

  def verifyResponseText(status: Status, expected: String)(
    implicit ev1: Eq[Status],
    ev2: Show[Status],
    run: RunSync[Task]
  ): Verified[String] =
    run
      .syncUnsafe(response)
      .fold(
        err => s"Should succeed but returned the error $err".invalidNel,
        res => res.status isSameAs status andThen { _ => verifiedResponseText(res, expected) }
      )

  private def verifiedResponse[A: EntityDecoder[Task, *]](res: Response[Task], check: A => Verified[A])(
    implicit run: RunSync[Task]
  ): Verified[A] =
    run
      .syncUnsafe(res.as[A])
      .fold(
        respErr => s"Response should succeed but returned the error $respErr".invalidNel,
        respRes => check(respRes)
      )

  private def verifiedResponseText[A](res: Response[Task], expected: String)(
    implicit run: RunSync[Task]
  ): Verified[String] =
    run
      .syncUnsafe(res.body.compile.toVector)
      .map(_.toArray)
      .fold(
        respErr => s"Response should succeed but returned the error $respErr".invalidNel,
        respMsg => new String(respMsg, StandardCharsets.UTF_8) isSameAs expected
      )
}

private[syntax] class VerifiedOps[A](private val a: A) extends AnyVal {
  def isNotSameAs(expected: =>A)(implicit ev1: Eq[A], ev2: Show[A]): Verified[A] =
    Validated.condNel(
      a =!= expected,
      a,
      s"Unexpected value. Expected different from ${expected.show} but was ${a.show}"
    )

  def isSameAs(expected: =>A)(implicit ev1: Eq[A], ev2: Show[A]): Verified[A] =
    Validated.condNel(a === expected, a, s"Unexpected value. Expected ${expected.show} but was ${a.show}")

  def is(p: A => Boolean, reason: =>String = "")(implicit ev: Show[A]): Verified[A] =
    Validated.condNel(p(a), a, s"Unexpected value ${a.show}: Reason $reason")
}

private[syntax] class VerifiedOptionOps[A](private val a: Option[A]) extends AnyVal {
  def isNotEmpty: Verified[Option[A]] =
    Validated.condNel(a.isDefined, a, s"Unexpected empty option value")
} 
Example 13
Source File: Http4sRpcTransport.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.network.rpc.http

import cats.effect.ConcurrentEffect
import jbok.network.rpc.{RpcRequest, RpcResponse, RpcTransport}
import org.http4s.client.blaze.BlazeClientBuilder
import org.http4s.{EntityDecoder, EntityEncoder, Method, Request, Uri}

import scala.concurrent.ExecutionContext

final class Http4sRpcTransport[F[_], P](
    baseUri: Uri
)(implicit F: ConcurrentEffect[F], entityEncoder: EntityEncoder[F, P], entityDecoder: EntityDecoder[F, RpcResponse[P]])
    extends RpcTransport[F, P] {

  override def fetch(request: RpcRequest[P]): F[RpcResponse[P]] = {
    val uri = request.path.foldLeft(baseUri)(_ / _)

    val req = Request[F](Method.POST, uri = uri).withEntity(request.payload)

    BlazeClientBuilder[F](ExecutionContext.global).resource.use { client =>
      client.fetchAs[RpcResponse[P]](req)
    }
  }
} 
Example 14
Source File: Main.scala    From http4s-poc-api   with MIT License 5 votes vote down vote up
package server

import java.util.concurrent.Executors

import com.github.ghik.silencer.silent
import external.{TeamOneHttpApi, TeamThreeCacheApi, TeamTwoHttpApi}
import io.circe.generic.auto._
import log.effect.zio.ZioLogWriter._
import model.DomainModel._
import org.http4s.circe._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._
import org.http4s.{EntityDecoder, EntityEncoder, HttpApp}
import service.PriceService
import zio.interop.catz._
import zio.interop.catz.implicits._
import zio.{ExitCode, RIO, Task, ZEnv, ZIO}

import scala.concurrent.ExecutionContext
import model.DomainModelCodecs._

@silent
object Main extends zio.interop.catz.CatsApp with Pools with Codecs {
  private[this] val priceService: RIO[String, PriceService[Task]] =
    log4sFromName map { log =>
      PriceService[Task](
        TeamThreeCacheApi.productCache,
        TeamOneHttpApi(),
        TeamTwoHttpApi(),
        log
      )
    }

  private[this] val httpApp: RIO[PriceService[Task], HttpApp[Task]] =
    ZIO.access { ps =>
      Router(
        "/pricing-api/prices"       -> PriceRoutes[Task].make(ps),
        "/pricing-api/health-check" -> HealthCheckRoutes[Task].make(ps.logger)
      ).orNotFound
    }

  private[this] val runningServer: RIO[HttpApp[Task], Unit] =
    ZIO.accessM { app =>
      BlazeServerBuilder[Task](serverPool)
        .bindHttp(17171, "0.0.0.0")
        .withConnectorPoolSize(connectorPoolSize)
        .enableHttp2(true)
        .withHttpApp(app)
        .serve
        .compile
        .drain
    }

  private[this] val serviceRuntime: RIO[String, Unit] =
    priceService >>> httpApp >>> runningServer

  def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] =
    serviceRuntime.fold(_ => ExitCode.failure, _ => ExitCode.success) provide "App log"
}

sealed trait Pools {

  protected val connectorPoolSize = Runtime.getRuntime.availableProcessors() * 2
  protected val mainThreadNumber  = Runtime.getRuntime.availableProcessors() + 1

  protected val serverPool = ExecutionContext.fromExecutor(
    Executors.newWorkStealingPool(mainThreadNumber)
  )
}

sealed trait Codecs {
  implicit val priceRequestPayloadDecoder: EntityDecoder[Task, PricesRequestPayload] =
    jsonOf[Task, PricesRequestPayload]

  implicit val priceResponsePayloadEncoder: EntityEncoder[Task, List[Price]] =
    jsonEncoderOf[Task, List[Price]]

  implicit val healthCheckResponsePayloadEncoder: EntityEncoder[Task, ServiceSignature] =
    jsonEncoderOf[Task, ServiceSignature]
} 
Example 15
Source File: BidderHttpAppBuilder.scala    From scala-openrtb   with Apache License 2.0 5 votes vote down vote up
package com.powerspace.openrtb.examples.rtb.http4s.bidder

import com.google.openrtb.BidRequest
import com.powerspace.openrtb.examples.rtb.http4s.common.ExampleSerdeModule
import io.circe.Decoder
import monix.eval.Task
import org.http4s.dsl.Http4sDsl
import org.http4s.{EntityDecoder, HttpApp}

object BidderHttpAppBuilder {

  private val bidder = new Bidder[Task]
  private val dsl = Http4sDsl[Task]
  private val serdeModule = ExampleSerdeModule

  
  private def handleBid(bidRequest: BidRequest) = {
    import dsl._
    import org.http4s.circe._

    bidder
      .bidOn(bidRequest)
      .flatMap {
        case Some(bidResponse) =>
          // encode the bidResponse to a json object as part of the http response body
          Ok(serdeModule.bidResponseEncoder(bidResponse))
        case None =>
          Ok()
      }
  }
} 
Example 16
Source File: AdserverHttpClientBuilder.scala    From scala-openrtb   with Apache License 2.0 5 votes vote down vote up
package com.powerspace.openrtb.examples.rtb.http4s.adserver

import com.google.openrtb.{BidRequest, BidResponse}
import com.powerspace.openrtb.examples.rtb.http4s.common.ExampleSerdeModule
import com.powerspace.openrtb.json.SerdeModule
import io.circe.{Decoder, Encoder}
import monix.eval.Task
import org.http4s.Uri.{Authority, RegName, Scheme}
import org.http4s.client.Client
import org.http4s.{EntityDecoder, EntityEncoder, Method, Request, Uri}

object AdserverHttpClientBuilder {

  import org.http4s.circe._

  val serdeModule: SerdeModule = ExampleSerdeModule

  implicit val bidRequestEncoder: Encoder[BidRequest] = serdeModule.bidRequestEncoder
  implicit val bidRequestEntityEncoder: EntityEncoder[Task, BidRequest] = jsonEncoderOf[Task, BidRequest]

  implicit val bidResponseDecoder: Decoder[BidResponse] = serdeModule.bidResponseDecoder
  implicit val bidResponseEntityDecoder: EntityDecoder[Task, BidResponse] = jsonOf[Task, BidResponse]

  def bid(client: Client[Task], bidRequest: BidRequest): Task[Option[BidResponse]] = {
    val url = Uri(
      scheme = Some(Scheme.http),
      authority = Some(Authority(host = RegName("localhost"), port = Some(9000))),
      path = "/bid"
    )

    val httpRequest = Request[Task](
      method = Method.POST,
      uri = url
    ).withEntity[BidRequest](bidRequest)

    client.expectOption[BidResponse](httpRequest)
  }
} 
Example 17
Source File: LoginTest.scala    From scala-pet-store   with Apache License 2.0 5 votes vote down vote up
package io.github.pauljamescleary.petstore
package infrastructure.endpoint

import cats.data.Kleisli
import cats.effect.IO
import domain.authentication.{LoginRequest, SignupRequest}
import domain.users.{Role, User}
import org.http4s.circe.{jsonEncoderOf, jsonOf}
import org.http4s.client.dsl.Http4sClientDsl
import org.http4s.{EntityDecoder, EntityEncoder, HttpApp, Request, Response}
import org.http4s.implicits._
import org.http4s.headers.Authorization
import io.circe.generic.auto._
import org.http4s.dsl.Http4sDsl

trait LoginTest extends Http4sClientDsl[IO] with Http4sDsl[IO] {
  implicit val userEnc: EntityEncoder[IO, User] = jsonEncoderOf
  implicit val userDec: EntityDecoder[IO, User] = jsonOf

  implicit val signUpRequestEnc: EntityEncoder[IO, SignupRequest] = jsonEncoderOf
  implicit val signUpRequestDec: EntityDecoder[IO, SignupRequest] = jsonOf

  implicit val loginRequestEnc: EntityEncoder[IO, LoginRequest] = jsonEncoderOf
  implicit val loginRequestDec: EntityDecoder[IO, LoginRequest] = jsonOf

  def signUpAndLogIn(
      userSignUp: SignupRequest,
      userEndpoint: HttpApp[IO],
  ): IO[(User, Option[Authorization])] =
    for {
      signUpRq <- POST(userSignUp, uri"/users")
      signUpResp <- userEndpoint.run(signUpRq)
      user <- signUpResp.as[User]
      loginBody = LoginRequest(userSignUp.userName, userSignUp.password)
      loginRq <- POST(loginBody, uri"/users/login")
      loginResp <- userEndpoint.run(loginRq)
    } yield {
      user -> loginResp.headers.get(Authorization)
    }

  def signUpAndLogInAsAdmin(
      userSignUp: SignupRequest,
      userEndpoint: Kleisli[IO, Request[IO], Response[IO]],
  ): IO[(User, Option[Authorization])] =
    signUpAndLogIn(userSignUp.copy(role = Role.Admin), userEndpoint)

  def signUpAndLogInAsCustomer(
      userSignUp: SignupRequest,
      userEndpoint: Kleisli[IO, Request[IO], Response[IO]],
  ): IO[(User, Option[Authorization])] =
    signUpAndLogIn(userSignUp.copy(role = Role.Customer), userEndpoint)
} 
Example 18
Source File: Proxy.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client.operation

import cats.effect.Sync
import com.goyeau.kubernetes.client.KubeConfig
import org.http4s._
import org.http4s.dsl.impl.Path
import org.http4s.client.Client
import org.http4s.EntityDecoder
import org.http4s.headers.`Content-Type`

private[client] trait Proxy[F[_]] {
  protected def httpClient: Client[F]
  implicit protected val F: Sync[F]
  protected def config: KubeConfig
  protected def resourceUri: Uri

  def proxy(
      name: String,
      method: Method,
      path: Path,
      contentType: `Content-Type` = `Content-Type`(MediaType.text.plain),
      data: Option[String] = None
  ): F[String] =
    httpClient.expect[String](
      Request(
        method,
        config.server.resolve(resourceUri) / name / s"proxy$path",
        headers = Headers(config.authorization.toList),
        body = data.fold[EntityBody[F]](EmptyBody)(
          implicitly[EntityEncoder[F, String]].withContentType(contentType).toEntity(_).body
        )
      )
    )(EntityDecoder.text)
} 
Example 19
Source File: TestRoutes.scala    From scala-server-lambda   with MIT License 5 votes vote down vote up
package io.github.howardjohn.lambda.http4s

import cats.{Applicative, MonadError}
import cats.effect.Sync
import cats.implicits._
import io.github.howardjohn.lambda.LambdaHandlerBehavior
import io.github.howardjohn.lambda.LambdaHandlerBehavior._
import org.http4s.dsl.Http4sDsl
import org.http4s.{EntityDecoder, Header, HttpRoutes}
import org.http4s.circe._
import io.circe.generic.auto._
import io.circe.syntax._
import org.http4s.dsl.impl.OptionalQueryParamDecoderMatcher

class TestRoutes[F[_]] {

  object TimesQueryMatcher extends OptionalQueryParamDecoderMatcher[Int]("times")

  val dsl = Http4sDsl[F]

  import dsl._

  def routes(implicit sync: Sync[F],
             jsonDecoder: EntityDecoder[F, JsonBody],
             me: MonadError[F, Throwable],
             stringDecoder: EntityDecoder[F, String],
             ap: Applicative[F]): HttpRoutes[F] = HttpRoutes.of[F] {
    case GET -> Root / "hello" :? TimesQueryMatcher(times) =>
      Ok {
        Seq
          .fill(times.getOrElse(1))("Hello World!")
          .mkString(" ")
      }
    case GET -> Root / "long" => Applicative[F].pure(Thread.sleep(1000)).flatMap(_ => Ok("Hello World!"))
    case GET -> Root / "exception" => throw RouteException()
    case GET -> Root / "error" => InternalServerError()
    case req@GET -> Root / "header" =>
      val header = req.headers.find(h => h.name.value == inputHeader).map(_.value).getOrElse("Header Not Found")
      Ok(header, Header(outputHeader, outputHeaderValue))
    case req@POST -> Root / "post" => req.as[String].flatMap(s => Ok(s))
    case req@POST -> Root / "json" => req.as[JsonBody].flatMap(s => Ok(LambdaHandlerBehavior.jsonReturn.asJson))
  }

} 
Example 20
Source File: Http4sSpec.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.cpgserver.route

import cats.effect.IO
import org.http4s.{EntityDecoder, Response, Status}

import io.shiftleft.cpgserver.BaseSpec

trait Http4sSpec extends BaseSpec {

  // Helpfully lifted from https://http4s.org/v0.20/testing/
  def check[A](actual: IO[Response[IO]], expectedStatus: Status, expectedBody: Option[A] = None)(
      implicit ev: EntityDecoder[IO, A]
  ): Boolean = {
    val actualResp = actual.unsafeRunSync
    val statusCheck = actualResp.status == expectedStatus
    val bodyCheck =
      expectedBody.fold[Boolean](actualResp.body.compile.toVector.unsafeRunSync.isEmpty)( // Verify Response's body is empty.
        expected => actualResp.as[A].unsafeRunSync == expected)
    statusCheck && bodyCheck
  }
} 
Example 21
Source File: HttpUploadTest.scala    From temperature-machine   with Apache License 2.0 5 votes vote down vote up
package bad.robot.temperature.client

import java.net.InetAddress

import bad.robot.temperature.rrd.{Host, Seconds}
import bad.robot.temperature.{IpAddress, Measurement, SensorReading, Temperature, UnexpectedError, jsonEncoder}
import cats.data.Kleisli
import cats.effect.IO
import org.http4s.Method.PUT
import org.http4s.client.{DisposableResponse, Client => Http4sClient}
import org.http4s.dsl.io._
import org.http4s.{EntityDecoder, Request}
import org.specs2.matcher.DisjunctionMatchers._
import org.specs2.mutable.Specification

class HttpUploadTest extends Specification {

  "Ip address pre-check" >> {
    IpAddress.currentIpAddress.size must be_>(0)
  }
  
  "Encode a measurement for the wire" >> {
    def encodeMessageViaEntityEncoder(measurement: Measurement): String = {
      implicit val encoder = jsonEncoder[Measurement]
      val request: IO[Request[IO]] = Request(PUT).withBody(measurement)
      EntityDecoder.decodeString(request.unsafeRunSync()).unsafeRunSync()
    }

    val measurement = Measurement(Host("example"), Seconds(1509221361), List(SensorReading("28-0115910f5eff", Temperature(19.75))))
    encodeMessageViaEntityEncoder(measurement) must_== """|{
                                                          |  "host" : {
                                                          |    "name" : "example",
                                                          |    "utcOffset" : null,
                                                          |    "timezone" : null
                                                          |  },
                                                          |  "seconds" : 1509221361,
                                                          |  "sensors" : [
                                                          |    {
                                                          |      "name" : "28-0115910f5eff",
                                                          |      "temperature" : {
                                                          |        "celsius" : 19.75
                                                          |      }
                                                          |    }
                                                          |  ]
                                                          |}""".stripMargin
  }
  
  "Error response from server" >> {
    val measurement = Measurement(Host("example"), Seconds(1509221361), List(SensorReading("28-0115910f5eff", Temperature(19.75))))
    
    val error = InternalServerError("I'm an error").map(DisposableResponse(_, IO.pure(())))
    val willError: Kleisli[IO, Request[IO], DisposableResponse[IO]] = new Kleisli[IO, Request[IO], DisposableResponse[IO]](_ => error)
    
    val client = Http4sClient[IO](willError, IO.pure(()))

    val upload = HttpUpload(InetAddress.getLoopbackAddress, client)
    val value = upload.write(measurement)
    value must be_-\/.like {
      case UnexpectedError("""Failed to PUT temperature data to http://127.0.0.1:11900/temperature, response was 500 Internal Server Error: Right(I'm an error)""") => ok
    }
  }
  
  "Request has headers" >> {
    val measurement = Measurement(Host("example"), Seconds(1509221361), List(SensorReading("28-0115910f5eff", Temperature(19.75))))
    
    var headers = List[String]()
    
    val client = Http4sClient[IO](new Kleisli[IO, Request[IO], DisposableResponse[IO]](request => {
      headers = request.headers.map(_.name.toString()).toList
      Ok().map(DisposableResponse(_, IO.pure(())))
    }), IO.pure(()))

    val upload = HttpUpload(InetAddress.getLoopbackAddress, client)
    upload.write(measurement)
    
    headers must_== List(
      "Content-Type",
      "X-Forwarded-For",
      "Content-Length"
    )
  }
} 
Example 22
Source File: package.scala    From temperature-machine   with Apache License 2.0 5 votes vote down vote up
package bad.robot

import java.io.{File, PrintWriter, StringWriter}

import cats.effect.IO
import cats.syntax.either._
import io.circe._
import org.http4s.circe.{jsonEncoderWithPrinterOf, jsonOf}
import io.circe.parser._
import org.http4s.{EntityDecoder, EntityEncoder}

import scalaz.\/
import scalaz.syntax.std.either._

package object temperature {

  type Degrees = Int

  // NB not implicit as this seems to clash with http4s implicits that are kicking around
  def jsonDecoder[A: Decoder]: EntityDecoder[IO, A] = jsonOf[IO, A]
  def jsonEncoder[A: Encoder]: EntityEncoder[IO, A] = jsonEncoderWithPrinterOf(spaces2PlatformSpecific)

  def encode[A: Encoder](a: A): Json = Encoder[A].apply(a)

  // deprecated
  def decodeAsDisjunction[A: Decoder](value: String): temperature.Error \/ A = {
    decode(value)
      .leftMap(error => ParseError(error.getMessage))
      .disjunction
  }

  def stackTraceOf(error: Throwable): String = {
    val writer = new StringWriter()
    error.printStackTrace(new PrintWriter(writer))
    writer.toString
  }

  private val eol = sys.props("line.separator")
  val spaces2PlatformSpecific = Printer(
    preserveOrder = true
    , dropNullValues = false
    , indent = "  "
    , lbraceLeft = ""
    , lbraceRight = eol
    , rbraceLeft = eol
    , rbraceRight = ""
    , lbracketLeft = ""
    , lbracketRight = eol
    , rbracketLeft = eol
    , rbracketRight = ""
    , lrbracketsEmpty = ""
    , arrayCommaLeft = ""
    , arrayCommaRight = eol
    , objectCommaLeft = ""
    , objectCommaRight = eol
    , colonLeft = " "
    , colonRight = " "
  )

  implicit class JsonOps(json: Json) {
    
    def spaces2ps: String = spaces2PlatformSpecific.pretty(json)
  }

  implicit class FileOps(file: File) {
    def /(child: String): File = new File(file, child)
  }

} 
Example 23
Source File: Http4sCirceInstances.scala    From pure-movie-server   with Apache License 2.0 5 votes vote down vote up
package pms.http

import fs2.Chunk
import io.circe.Printer
import pms.effects._
import pms.json._
import org.http4s._
import org.http4s.headers.`Content-Type`
import org.http4s.{EntityDecoder, EntityEncoder}
import org.http4s.circe.CirceInstances


  implicit def syncEntityJsonEncoder[F[_]: Applicative, T: Encoder]: EntityEncoder[F, T] =
    EntityEncoder[F, Chunk[Byte]]
      .contramap[Json] { json =>
        val bytes = printer.printToByteBuffer(json)
        Chunk.byteBuffer(bytes)
      }
      .withContentType(`Content-Type`(MediaType.application.json))
      .contramap(t => Encoder.apply[T].apply(t))

  implicit def syncEntityJsonDecoder[F[_]: Sync, T: Decoder]: EntityDecoder[F, T] =
    circeInstances.jsonOf[F, T]

}

object Http4sCirceInstances {
  private val printer:        Printer        = Printer.noSpaces.copy(dropNullValues = true)

  private val circeInstances: CirceInstances =
    CirceInstances.withPrinter(printer).build
} 
Example 24
Source File: MavenCentralClient.scala    From zorechka-bot   with MIT License 5 votes vote down vote up
package com.wix.zorechka.clients

import com.wix.zorechka.Dep
import org.http4s.{EntityDecoder, Header, Headers, Method, Request, Uri}
import zio.{Task, ZIO}
import zio.interop.catz._
import io.circe.generic.auto._
import org.http4s.circe.jsonOf
import org.http4s.client.Client

trait MavenCentralClient {
  val client: MavenCentralClient.Service
}

object MavenCentralClient {
  trait Service {
    def allVersions(dep: Dep): Task[List[Dep]]
  }

  trait Live extends MavenCentralClient {
    protected val httpClient: Client[Task]

    val client = new MavenCentralClient.Service {
      case class Response(response: InnerResponse)
      case class InnerResponse(docs: Seq[Document])
      case class Document(v: String)

      implicit val decoder: EntityDecoder[Task, Response] = jsonOf[Task, Response]

      override def allVersions(dep: Dep): Task[List[Dep]] = {
        ZIO.accessM {
          client =>
            val uri = Uri
              .unsafeFromString("http://search.maven.org/solrsearch/select")
              .withQueryParam("rows", "10")
              .withQueryParam("core", "gav")
              .withQueryParam("q", s""" g:"${dep.groupId}" AND a:"${dep.artifactId}" """)
            println(s"Maven search: ${uri.renderString}")

            val request = Request[Task](Method.GET, uri, headers = Headers.of(Header("Accept", "application/json")))

            httpClient.fetch(request)(response => response.as[Response]).map {
              _.response.docs.map(_.v).map(v => Dep(dep.groupId, dep.artifactId, v)).toList
            }
        }
      }
    }
  }
}