org.http4s.Method Scala Examples

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

import cats.effect.Sync
import log.effect.LogWriter
import model.DomainModel._
import org.http4s.dsl.Http4sDsl
import org.http4s.{EntityEncoder, HttpRoutes, Method}
import cats.syntax.flatMap._

sealed abstract class HealthCheckRoutes[F[_]: Sync](
  implicit responseEncoder: EntityEncoder[F, ServiceSignature]
) extends Http4sDsl[F] {
  def make(log: LogWriter[F]): HttpRoutes[F] =
    HttpRoutes.of[F] {
      case Method.GET -> Root => log.debug(s"Serving HealthCheck request") >> Ok(serviceSignature)
    }

  private val serviceSignature =
    ServiceSignature(
      name = BuildInfo.name,
      version = BuildInfo.version,
      scalaVersion = BuildInfo.scalaVersion,
      scalaOrganization = BuildInfo.scalaOrganization,
      buildTime = BuildInfo.buildTime
    )
}

object HealthCheckRoutes {
  def apply[F[_]: Sync: EntityEncoder[*[_], ServiceSignature]]: HealthCheckRoutes[F] =
    new HealthCheckRoutes[F] {}
} 
Example 2
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 3
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 4
Source File: PutObject.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.s3

import cats.effect.Effect
import org.aws4s.{PayloadSigning, _}
import org.http4s.Method
import fs2.Stream

private[aws4s] case class PutObject[F[_]: Effect](
    region:         Region,
    bucketName:     BucketName,
    objectPath:     ObjectPath,
    obj:            F[Stream[F, Byte]],
    payloadSigning: PayloadSigning
) extends S3ObjectCommand[F, Unit] {

  override val action:  Method             = Method.PUT
  override val payload: F[Stream[F, Byte]] = obj
} 
Example 5
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 6
Source File: DynamoDbCommand.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.dynamodb

import cats.effect.Effect
import io.circe.{Decoder, Json}
import org.aws4s.PayloadSigning
import org.http4s.headers.{Host, `Content-Type`}
import org.http4s.{Header, Headers, MediaType, Method, Request, Uri}
import org.http4s.circe._
import cats.implicits._
import org.aws4s.core.ExtraEntityDecoderInstances._
import org.aws4s.core.{Command, CommandPayload, RenderedParam, ServiceName}

private[dynamodb] abstract class DynamoDbCommand[F[_]: Effect, R: Decoder] extends Command[F, Json, R] {
  override def serviceName:    ServiceName    = ServiceName.DynamoDb
  override def payloadSigning: PayloadSigning = PayloadSigning.Signed

  def action: String

  override final val requestGenerator: List[RenderedParam[Json]] => F[Request[F]] = params => {
    val host = s"dynamodb.${region.name}.amazonaws.com"
    val payload: Json = CommandPayload.jsonObject(params)
    Request[F](
      Method.POST,
      Uri.unsafeFromString(s"https://$host/"),
      headers = Headers(Header("X-Amz-Target", s"DynamoDB_20120810.$action"), Host(host))
    ).withBody(payload).map(_.withContentType(`Content-Type`.apply(MediaType.fromKey(("application", "x-amz-json-1.0")))))
  }
} 
Example 7
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 8
Source File: KmsCommand.scala    From aws4s   with MIT License 5 votes vote down vote up
package org.aws4s.kms

import cats.effect.Effect
import cats.implicits._
import io.circe.{Decoder, Json}
import org.aws4s.core.ExtraEntityDecoderInstances._
import org.aws4s._
import org.aws4s.core.{Command, CommandPayload, RenderedParam, ServiceName}
import org.http4s.circe._
import org.http4s.headers.{Host, `Content-Type`}
import org.http4s.{Header, Headers, MediaType, Method, Request, Uri}

private[kms] abstract class KmsCommand[F[_]: Effect, R: Decoder] extends Command[F, Json, R] {
  override def serviceName:    ServiceName    = ServiceName.Kms
  override def payloadSigning: PayloadSigning = PayloadSigning.Signed

  def action: String

  override final val requestGenerator: List[RenderedParam[Json]] => F[Request[F]] = { params =>
    val host = s"kms.${region.name}.amazonaws.com"
    val payload: Json = CommandPayload.jsonObject(params)
    Request[F](
      Method.POST,
      Uri.unsafeFromString(s"https://$host/"),
      headers = Headers(Header("X-Amz-Target", s"TrentService.$action"), Host(host))
    ).withBody(payload).map(_.withContentType(`Content-Type`.apply(MediaType.fromKey(("application", "x-amz-json-1.1")))))
  }
} 
Example 9
Source File: MicrometerHttp4sMetricsOpsModuleTest.scala    From scala-server-toolkit   with MIT License 5 votes vote down vote up
package com.avast.sst.http4s.server.micrometer

import java.util.concurrent.TimeUnit

import cats.effect.IO
import io.micrometer.core.instrument.simple.SimpleMeterRegistry
import org.http4s.{Method, Status}
import org.scalatest.funsuite.AnyFunSuite

class MicrometerHttp4sMetricsOpsModuleTest extends AnyFunSuite {

  test("http4s MetricsOps for Micrometer") {
    val registry = new SimpleMeterRegistry()
    val metricsOps = MicrometerHttp4sMetricsOpsModule.make[IO](registry).unsafeRunSync()

    metricsOps.increaseActiveRequests(None).unsafeRunSync()
    metricsOps.recordTotalTime(Method.GET, Status.Ok, 2500, None).unsafeRunSync()

    assert(registry.get("http.global.active-requests").gauge().value() === 1)
    assert(registry.get("http.global.total-time").timer().count() === 1)
    assert(registry.get("http.global.total-time").timer().totalTime(TimeUnit.NANOSECONDS) > 2499)
    assert(registry.get("http.global.total-time").tags("status", "200").timer().count() === 1)
    assert(registry.get("http.global.total-time").tags("status-class", "2xx").timer().count() === 1)
  }

} 
Example 10
Source File: MicrometerHttp4sMetricsOpsModule.scala    From scala-server-toolkit   with MIT License 5 votes vote down vote up
package com.avast.sst.http4s.server.micrometer

import java.util.concurrent.TimeUnit

import cats.effect.Effect
import cats.effect.concurrent.Ref
import cats.syntax.functor._
import io.micrometer.core.instrument.MeterRegistry
import org.http4s.metrics.{MetricsOps, TerminationType}
import org.http4s.{Method, Status}

object MicrometerHttp4sMetricsOpsModule {

  
  def make[F[_]: Effect](meterRegistry: MeterRegistry): F[MetricsOps[F]] = {
    val F = Effect[F]

    for {
      activeRequests <- Ref.of[F, Long](0L)
    } yield new MetricsOps[F] {

      private val prefix = "http.global"
      private val failureTime = meterRegistry.timer(s"$prefix.failure-time")

      meterRegistry.gauge(
        s"$prefix.active-requests",
        activeRequests,
        (_: Ref[F, Long]) => Effect[F].toIO(activeRequests.get).unsafeRunSync().toDouble
      )

      override def increaseActiveRequests(classifier: Option[String]): F[Unit] = activeRequests.update(_ + 1)

      override def decreaseActiveRequests(classifier: Option[String]): F[Unit] = activeRequests.update(_ - 1)

      override def recordHeadersTime(method: Method, elapsed: Long, classifier: Option[String]): F[Unit] = {
        F.delay(meterRegistry.timer(s"$prefix.headers-time", "method", method.name).record(elapsed, TimeUnit.NANOSECONDS))
      }

      override def recordTotalTime(method: Method, status: Status, elapsed: Long, classifier: Option[String]): F[Unit] = {
        F.delay(
          meterRegistry
            .timer(s"$prefix.total-time", "status", s"${status.code}", "status-class", s"${status.code / 100}xx")
            .record(elapsed, TimeUnit.NANOSECONDS)
        )
      }

      override def recordAbnormalTermination(elapsed: Long, terminationType: TerminationType, classifier: Option[String]): F[Unit] = {
        F.delay(failureTime.record(elapsed, TimeUnit.NANOSECONDS))
      }

    }
  }

} 
Example 11
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 12
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 13
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 14
Source File: DefaultMetricsOps.scala    From datadog4s   with MIT License 5 votes vote down vote up
package com.avast.datadog4s.extension.http4s.impl

import java.time.Duration

import cats.effect.Sync
import cats.effect.concurrent.Ref
import cats.syntax.flatMap._
import com.avast.datadog4s.api.MetricFactory
import com.avast.datadog4s.api.tag.Tagger
import com.avast.datadog4s.extension.http4s.DatadogMetricsOps.ClassifierTags
import com.avast.datadog4s.extension.http4s._
import com.github.ghik.silencer.silent
import org.http4s.metrics.{ MetricsOps, TerminationType }
import org.http4s.{ Method, Status }

private[http4s] class DefaultMetricsOps[F[_]](
  metricFactory: MetricFactory[F],
  classifierTags: ClassifierTags,
  activeConnectionsRef: Ref[F, ActiveConnections]
)(implicit
  F: Sync[F]
) extends MetricsOps[F] {
  private[this] val methodTagger          = Tagger.make[Method]("method")
  @deprecated("please use terminationTypeTagger - this will be removed in next release 0.8.0", "0.6.3")
  private[this] val typeTagger            = Tagger.make[TerminationType]("type")
  private[this] val terminationTypeTagger = Tagger.make[TerminationType]("termination_type")
  private[this] val statusCodeTagger      = Tagger.make[Status]("status_code")
  private[this] val statusBucketTagger    = Tagger.make[String]("status_bucket")
  private[this] val activeRequests        = metricFactory.gauge.long("active_requests")

  override def increaseActiveRequests(classifier: Option[String]): F[Unit] =
    modifyActiveRequests(classifier, 0, 1)

  override def decreaseActiveRequests(classifier: Option[String]): F[Unit] =
    // if we try to decrement non existing classifier, make sure it's zero
    modifyActiveRequests(classifier, 1, -1)

  private def modifyActiveRequests(classifier: Option[String], default: Int, delta: Int): F[Unit] =
    activeConnectionsRef.modify { activeConnections =>
      val current               = activeConnections.getOrElse(classifier, default)
      val next                  = current + delta
      val nextActiveConnections = activeConnections.updated(classifier, next)
      val action                = activeRequests.set(
        next.toLong,
        classifier.toList.flatMap(classifierTags): _*
      )
      (nextActiveConnections, action)
    }.flatten

  private[this] val headersTime = metricFactory.timer("headers_time")

  override def recordHeadersTime(method: Method, elapsed: Long, classifier: Option[String]): F[Unit] =
    headersTime
      .record(
        Duration.ofNanos(elapsed),
        methodTagger.tag(method) :: classifier.toList.flatMap(classifierTags): _*
      )

  private[this] val requestCount   = metricFactory.count("requests_count")
  private[this] val requestLatency = metricFactory.timer("requests_latency")
  override def recordTotalTime(method: Method, status: Status, elapsed: Long, classifier: Option[String]): F[Unit] = {
    val tags = methodTagger.tag(method) ::
      statusBucketTagger.tag(s"${status.code / 100}xx") ::
      statusCodeTagger.tag(status) :: classifier.toList.flatMap(classifierTags)
    requestCount.inc(tags: _*) >> requestLatency.record(Duration.ofNanos(elapsed), tags: _*)
  }

  private[this] val abnormalCount   = metricFactory.count("abnormal_count")
  private[this] val abnormalLatency = metricFactory.timer("abnormal_latency")
  override def recordAbnormalTermination(
    elapsed: Long,
    terminationType: TerminationType,
    classifier: Option[String]
  ): F[Unit] = {
    val terminationTpe = terminationTypeTagger.tag(terminationType)
    @silent("deprecated")
    val tpe            = typeTagger.tag(terminationType)
    val tags           = tpe :: terminationTpe :: classifier.toList.flatMap(classifierTags)
    abnormalCount.inc(tags: _*) >> abnormalLatency.record(Duration.ofNanos(elapsed), tags: _*)
  }
} 
Example 15
Source File: InfluxClient.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.cli.clients

import cats.effect.{Sync, Timer}
import cats.implicits._
import ch.epfl.bluebrain.nexus.cli._
import ch.epfl.bluebrain.nexus.cli.config.influx.InfluxConfig
import ch.epfl.bluebrain.nexus.cli.config.{AppConfig, EnvConfig}
import io.circe.Json
import org.http4s.client.Client
import org.http4s.{Method, Request, UrlForm}

trait InfluxClient[F[_]] {

  
  final def apply[F[_]: Sync: Timer](
      client: Client[F],
      config: AppConfig,
      console: Console[F]
  ): InfluxClient[F] = {
    implicit val c: Console[F] = console
    new LiveInfluxDbClient[F](client, config.influx, config.env)
  }
} 
Example 16
Source File: TestClient.scala    From franklin   with Apache License 2.0 5 votes vote down vote up
package com.azavea.franklin.api

import cats.effect.Resource
import cats.effect.Sync
import cats.implicits._
import com.azavea.franklin.api.services.{CollectionItemsService, CollectionsService}
import com.azavea.stac4s.{StacCollection, StacItem}
import eu.timepit.refined.auto._
import io.circe.syntax._
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.implicits._
import org.http4s.{Method, Request, Uri}

import java.net.URLEncoder
import java.nio.charset.StandardCharsets


class TestClient[F[_]: Sync](
    collectionsService: CollectionsService[F],
    collectionItemsService: CollectionItemsService[F]
) {

  private def createCollection(collection: StacCollection): F[StacCollection] =
    collectionsService.routes.orNotFound.run(
      Request(
        method = Method.POST,
        uri = Uri.unsafeFromString("/collections")
      ).withEntity(collection.asJson)
    ) flatMap { _.as[StacCollection] }

  private def deleteCollection(collection: StacCollection): F[Unit] = {
    val encodedCollectionId = URLEncoder.encode(collection.id, StandardCharsets.UTF_8.toString)
    collectionsService.routes.orNotFound
      .run(
        Request(
          method = Method.DELETE,
          uri = Uri.unsafeFromString(s"/collections/$encodedCollectionId")
        )
      )
      .void
  }

  private def createItemInCollection(collection: StacCollection, item: StacItem): F[StacItem] = {
    val encodedCollectionId = URLEncoder.encode(collection.id, StandardCharsets.UTF_8.toString)
    collectionItemsService.routes.orNotFound.run(
      Request(
        method = Method.POST,
        uri = Uri.unsafeFromString(s"/collections/$encodedCollectionId/items")
      ).withEntity(item)
    ) flatMap { _.as[StacItem] }
  }

  private def deleteItemInCollection(collection: StacCollection, item: StacItem): F[Unit] = {
    val encodedCollectionId = URLEncoder.encode(collection.id, StandardCharsets.UTF_8.toString)
    val encodedItemId       = URLEncoder.encode(item.id, StandardCharsets.UTF_8.toString)
    collectionItemsService.routes.orNotFound
      .run(
        Request(
          method = Method.DELETE,
          uri = Uri.unsafeFromString(s"/collections/$encodedCollectionId/items/$encodedItemId")
        )
      )
      .void
  }

  def getItemResource(collection: StacCollection, item: StacItem): Resource[F, StacItem] =
    Resource.make(createItemInCollection(collection, item.copy(collection = Some(collection.id))))(
      item => deleteItemInCollection(collection, item)
    )

  def getCollectionResource(collection: StacCollection): Resource[F, StacCollection] =
    Resource.make(createCollection(collection))(collection => deleteCollection(collection))

  def getCollectionItemResource(
      item: StacItem,
      collection: StacCollection
  ): Resource[F, (StacItem, StacCollection)] =
    (getItemResource(collection, item), getCollectionResource(collection)).tupled
} 
Example 17
Source File: CollectionsServiceSpec.scala    From franklin   with Apache License 2.0 5 votes vote down vote up
package com.azavea.franklin.api.services

import cats.data.OptionT
import cats.effect.IO
import cats.implicits._
import com.azavea.franklin.Generators
import com.azavea.franklin.api.{TestClient, TestServices}
import com.azavea.franklin.database.TestDatabaseSpec
import com.azavea.franklin.datamodel.CollectionsResponse
import com.azavea.stac4s.StacCollection
import com.azavea.stac4s.testing._
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.{Method, Request, Uri}
import org.specs2.{ScalaCheck, Specification}

import java.net.URLEncoder
import java.nio.charset.StandardCharsets

class CollectionsServiceSpec
    extends Specification
    with ScalaCheck
    with TestDatabaseSpec
    with Generators {
  def is = s2"""
  This specification verifies that the collections service can run without crashing

  The collections service should:
    - create and delete collections $createDeleteCollectionExpectation
    - list collections              $listCollectionsExpectation
    - get collections by id         $getCollectionsExpectation
"""

  val testServices: TestServices[IO] = new TestServices[IO](transactor)

  val testClient: TestClient[IO] =
    new TestClient[IO](testServices.collectionsService, testServices.collectionItemsService)

  def listCollectionsExpectation = prop {
    (stacCollectionA: StacCollection, stacCollectionB: StacCollection) =>
      {
        val listIO = (
          testClient.getCollectionResource(stacCollectionA),
          testClient.getCollectionResource(stacCollectionB)
        ).tupled use { _ =>
          val request = Request[IO](method = Method.GET, Uri.unsafeFromString(s"/collections"))
          (for {
            resp    <- testServices.collectionsService.routes.run(request)
            decoded <- OptionT.liftF { resp.as[CollectionsResponse] }
          } yield decoded).value
        }

        val result = listIO.unsafeRunSync.get.collections map { _.id }

        (result must contain(stacCollectionA.id)) and (result must contain(stacCollectionB.id))
      }
  }

  def getCollectionsExpectation = prop { (stacCollection: StacCollection) =>
    val fetchIO =
      testClient.getCollectionResource(stacCollection) use { collection =>
        val encodedId = URLEncoder.encode(collection.id, StandardCharsets.UTF_8.toString)
        val request =
          Request[IO](method = Method.GET, Uri.unsafeFromString(s"/collections/$encodedId"))
        (for {
          resp    <- testServices.collectionsService.routes.run(request)
          decoded <- OptionT.liftF { resp.as[StacCollection] }
        } yield (decoded, collection)).value
      }

    val (fetched, inserted) = fetchIO.unsafeRunSync.get

    fetched must beTypedEqualTo(inserted)
  }

  // since creation / deletion is a part of the collection resource, and accurate creation is checked
  // in getCollectionsExpectation, this test just makes sure that if other tests are failing, it's
  // not because create/delete are broken
  def createDeleteCollectionExpectation = prop { (stacCollection: StacCollection) =>
    (testClient
      .getCollectionResource(stacCollection) use { _ => IO.unit }).unsafeRunSync must beTypedEqualTo(
      ()
    )
  }

} 
Example 18
Source File: JoexClient.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.joexapi.client

import scala.concurrent.ExecutionContext

import cats.effect._
import cats.implicits._

import docspell.common.syntax.all._
import docspell.common.{Ident, LenientUri}
import docspell.joexapi.model.BasicResult

import org.http4s.circe.CirceEntityDecoder._
import org.http4s.client.Client
import org.http4s.client.blaze.BlazeClientBuilder
import org.http4s.{Method, Request, Uri}
import org.log4s.getLogger

trait JoexClient[F[_]] {

  def notifyJoex(base: LenientUri): F[Unit]

  def notifyJoexIgnoreErrors(base: LenientUri): F[Unit]

  def cancelJob(base: LenientUri, job: Ident): F[BasicResult]

}

object JoexClient {

  private[this] val logger = getLogger

  def apply[F[_]: Sync](client: Client[F]): JoexClient[F] =
    new JoexClient[F] {
      def notifyJoex(base: LenientUri): F[Unit] = {
        val notifyUrl = base / "api" / "v1" / "notify"
        val req       = Request[F](Method.POST, uri(notifyUrl))
        logger.fdebug(s"Notify joex at ${notifyUrl.asString}") *>
          client.expect[String](req).map(_ => ())
      }

      def notifyJoexIgnoreErrors(base: LenientUri): F[Unit] =
        notifyJoex(base).attempt.map {
          case Right(()) => ()
          case Left(ex) =>
            logger.warn(
              s"Notifying Joex instance '${base.asString}' failed: ${ex.getMessage}"
            )
            ()
        }

      def cancelJob(base: LenientUri, job: Ident): F[BasicResult] = {
        val cancelUrl = base / "api" / "v1" / "job" / job.id / "cancel"
        val req       = Request[F](Method.POST, uri(cancelUrl))
        client.expect[BasicResult](req)
      }

      private def uri(u: LenientUri): Uri =
        Uri.unsafeFromString(u.asString)
    }

  def resource[F[_]: ConcurrentEffect](ec: ExecutionContext): Resource[F, JoexClient[F]] =
    BlazeClientBuilder[F](ec).resource.map(apply[F])
} 
Example 19
Source File: HttpExistenceClient.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.util

import cats.effect.{Async, Resource}
import cats.implicits._
import com.github.benmanes.caffeine.cache.Caffeine
import io.chrisdavenport.log4cats.Logger
import org.http4s.client.Client
import org.http4s.{Method, Request, Status, Uri}
import org.scalasteward.core.application.Config
import scalacache.CatsEffect.modes._
import scalacache.caffeine.CaffeineCache
import scalacache.{Async => _, _}

final class HttpExistenceClient[F[_]](statusCache: Cache[Status])(implicit
    client: Client[F],
    logger: Logger[F],
    mode: Mode[F],
    F: MonadThrowable[F]
) {
  def exists(uri: Uri): F[Boolean] =
    status(uri).map(_ === Status.Ok).handleErrorWith { throwable =>
      logger.debug(throwable)(s"Failed to check if $uri exists").as(false)
    }

  private def status(uri: Uri): F[Status] =
    statusCache.cachingForMemoizeF(uri.renderString)(None) {
      client.status(Request[F](method = Method.HEAD, uri = uri))
    }
}

object HttpExistenceClient {
  def create[F[_]](implicit
      config: Config,
      client: Client[F],
      logger: Logger[F],
      F: Async[F]
  ): Resource[F, HttpExistenceClient[F]] = {
    val buildCache = F.delay {
      CaffeineCache(
        Caffeine
          .newBuilder()
          .maximumSize(16384L)
          .expireAfterWrite(config.cacheTtl.length, config.cacheTtl.unit)
          .build[String, Entry[Status]]()
      )
    }
    Resource.make(buildCache)(_.close().void).map(new HttpExistenceClient[F](_))
  }
} 
Example 20
Source File: ServerSpec.scala    From Learn-Scala-Programming   with MIT License 5 votes vote down vote up
import ch14.{Config, Server}
import cats.effect.IO
import cats.implicits._
import io.circe.Json
import io.circe.literal._
import org.http4s.circe._
import org.http4s.client.blaze.Http1Client
import org.http4s.{Method, Request, Status, Uri}
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpec}
import org.http4s.server.{Server => Http4sServer}

class ServerSpec extends WordSpec with Matchers with BeforeAndAfterAll {
  private lazy val client = Http1Client[IO]().unsafeRunSync()

  private lazy val configIO = Config.load("test.conf")
  private lazy val config = configIO.unsafeRunSync()

  private lazy val rootUrl = s"http://${config.server.host}:${config.server.port}"

  private val server: Option[Http4sServer[IO]] = (for {
    builder <- Server.createServer(configIO)
  } yield builder.start.unsafeRunSync()).compile.last.unsafeRunSync()


  override def afterAll(): Unit = {
    client.shutdown.unsafeRunSync()
    server.foreach(_.shutdown.unsafeRunSync())
  }

  "The server" should {
    "get an empty inventory" in {
      val json = client.expect[Json](s"$rootUrl/inventory").unsafeRunSync()
      json shouldBe json"""{}"""
    }
    "create articles" in {
      val eggs = Request[IO](method = Method.POST, uri = Uri.unsafeFromString(s"$rootUrl/articles/eggs"))
      client.status(eggs).unsafeRunSync() shouldBe Status.NoContent
      val chocolate = Request[IO](method = Method.POST, uri = Uri.unsafeFromString(s"$rootUrl/articles/chocolate"))
      client.status(chocolate).unsafeRunSync() shouldBe Status.NoContent
      val json = client.expect[Json](s"$rootUrl/inventory").unsafeRunSync()
      json shouldBe json"""{"eggs" : 0,"chocolate" : 0}"""
    }
    "update inventory" in {
      val restock = Request[IO](method = Method.POST, uri = Uri.unsafeFromString(s"$rootUrl/restock")).withBody(json"""{ "inventory" : { "eggs": 10, "chocolate": 20 }}""")
      client.expect[Json](restock).unsafeRunSync() shouldBe json"""{ "eggs" : 10, "chocolate" : 20 }"""
      client.expect[Json](restock).unsafeRunSync() shouldBe json"""{ "eggs" : 20, "chocolate" : 40 }"""
    }
    "deliver purchase if there is enough inventory" in {
      val purchase = Request[IO](method = Method.POST, uri = Uri.unsafeFromString(s"$rootUrl/purchase")).withBody(json"""{ "order" : { "eggs": 5, "chocolate": 5 }}""")
      client.expect[Json](purchase).unsafeRunSync() shouldBe json"""{ "eggs" : 5, "chocolate" : 5 }"""
    }
    "not deliver purchase if there is not enough inventory" in {
      val purchase = Request[IO](method = Method.POST, uri = Uri.unsafeFromString(s"$rootUrl/purchase")).withBody(json"""{ "order" : { "eggs": 5, "chocolate": 45 }}""")
      client.expect[Json](purchase).unsafeRunSync() shouldBe json"""{ "eggs" : 0, "chocolate" : 0 }"""
    }
  }

} 
Example 21
Source File: Github.scala    From sonar-scala   with GNU Lesser General Public License v3.0 5 votes vote down vote up
package com.mwz.sonar.scala
package pr
package github

import cats.effect.Sync
import cats.syntax.flatMap._
import com.mwz.sonar.scala.pr.github.Codec._
import io.circe.generic.auto._
import mouse.boolean._
import org.http4s.client.Client
import org.http4s.{Header, Headers, Method, Request, Uri}

trait Github[F[_]] {
  def authenticatedUser: F[User]
  def pullRequest: F[PullRequest]
  def comments: F[List[Comment]]
  def createComment(comment: NewComment): F[Unit]
  def files: F[List[File]]
  def createStatus(sha: String, status: NewStatus): F[Unit]
}

object Github {
  def apply[F[_]: Sync](client: Client[F], pr: GlobalConfig.PullRequest): Github[F] =
    new Github[F] {
      val auth: Header = Header("Authorization", s"token ${pr.github.oauth}")
      val userUri: Uri = pr.github.apiuri / "user"
      val prUri: Uri =
        (pr.github.apiuri / "repos").addPath(pr.github.repository) / "pulls" / pr.prNumber
      val commentsUri: Uri = prUri / "comments"
      val filesUri: Uri = prUri / "files"
      def newStatusUri(sha: String): Uri =
        (pr.github.apiuri / "repos").addPath(pr.github.repository) / "statuses" / sha
      def request(uri: Uri): Request[F] = {
        Request[F](
          uri = uri,
          headers = Headers.of(auth)
        )
      }
      def authenticatedUser: F[User] = client.expect[User](request(userUri))
      def pullRequest: F[PullRequest] = client.expect[PullRequest](request(prUri))
      def comments: F[List[Comment]] = client.expect[List[Comment]](request(commentsUri))
      def createComment(comment: NewComment): F[Unit] = {
        val request: F[Request[F]] = Sync[F].pure(
          Request(Method.POST, commentsUri, headers = Headers.of(auth))
            .withEntity(comment)
        )
        pr.dryRun.fold(Sync[F].unit, client.expect[Comment](request) >> Sync[F].unit)
      }
      def files: F[List[File]] = client.expect[List[File]](request(filesUri))
      def createStatus(sha: String, status: NewStatus): F[Unit] = {
        val request: F[Request[F]] = Sync[F].pure(
          Request(Method.POST, newStatusUri(sha), headers = Headers.of(auth))
            .withEntity(status)
        )
        pr.dryRun.fold(Sync[F].unit, client.expect[Status](request) >> Sync[F].unit)
      }
    }
} 
Example 22
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
            }
        }
      }
    }
  }
}