org.http4s.server.blaze.BlazeServerBuilder Scala Examples

The following examples show how to use org.http4s.server.blaze.BlazeServerBuilder. 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: MockHttpServer.scala    From cornichon   with Apache License 2.0 6 votes vote down vote up
package com.github.agourlay.cornichon.http.server

import java.net.NetworkInterface

import com.github.agourlay.cornichon.core.CornichonError
import monix.eval.Task
import monix.execution.Scheduler
import org.http4s.HttpRoutes
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.implicits._

import scala.jdk.CollectionConverters._
import scala.concurrent.duration._
import scala.util.Random

class MockHttpServer[A](interface: Option[String], port: Option[Range], mockService: HttpRoutes[Task], maxRetries: Int = 5)(useFromAddress: String => Task[A])(implicit scheduler: Scheduler) {

  private val selectedInterface = interface.getOrElse(bestInterface())
  private val randomPortOrder = port.fold(0 :: Nil)(r => Random.shuffle(r.toList))

  private val mockRouter = Router("/" -> mockService).orNotFound

  def useServer(): Task[A] =
    if (randomPortOrder.isEmpty)
      Task.raiseError(MockHttpServerError.toException)
    else
      startServerTryPorts(randomPortOrder)

  private def startServerTryPorts(ports: List[Int], retry: Int = 0): Task[A] =
    startBlazeServer(ports.head).onErrorHandleWith {
      case _: java.net.BindException if ports.length > 1 =>
        startServerTryPorts(ports.tail, retry)
      case _: java.net.BindException if retry < maxRetries =>
        val sleepFor = retry + 1
        println(s"Could not start server on any port. Retrying in $sleepFor seconds...")
        startServerTryPorts(randomPortOrder, retry = retry + 1).delayExecution(sleepFor.seconds)
    }

  private def startBlazeServer(port: Int): Task[A] =
    BlazeServerBuilder[Task](executionContext = scheduler)
      .bindHttp(port, selectedInterface)
      .withoutBanner
      .withHttpApp(mockRouter)
      .withNio2(true)
      .resource
      .use(server => useFromAddress(s"http://${server.address.getHostString}:${server.address.getPort}"))

  private def bestInterface(): String =
    NetworkInterface.getNetworkInterfaces.asScala
      .filter(_.isUp)
      .flatMap(_.getInetAddresses.asScala)
      .find(_.isSiteLocalAddress)
      .map(_.getHostAddress)
      .getOrElse("localhost")
}

case object MockHttpServerError extends CornichonError {
  val baseErrorMessage = "the range of ports provided for the HTTP mock is invalid"
} 
Example 2
Source File: MultipleEndpointsDocumentationHttp4sServer.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.examples

import java.util.concurrent.atomic.AtomicReference

import cats.effect._
import cats.implicits._
import com.github.ghik.silencer.silent
import io.circe.generic.auto._
import org.http4s.HttpRoutes
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._
import sttp.tapir._
import sttp.tapir.docs.openapi._
import sttp.tapir.json.circe._
import sttp.tapir.openapi.OpenAPI
import sttp.tapir.openapi.circe.yaml._
import sttp.tapir.server.http4s._
import sttp.tapir.swagger.http4s.SwaggerHttp4s

import scala.concurrent.ExecutionContext

object MultipleEndpointsDocumentationHttp4sServer extends App {
  // endpoint descriptions
  case class Author(name: String)
  case class Book(title: String, year: Int, author: Author)

  val booksListing: Endpoint[Unit, Unit, Vector[Book], Nothing] = endpoint.get
    .in("books")
    .in("list" / "all")
    .out(jsonBody[Vector[Book]])

  val addBook: Endpoint[Book, Unit, Unit, Nothing] = endpoint.post
    .in("books")
    .in("add")
    .in(
      jsonBody[Book]
        .description("The book to add")
        .example(Book("Pride and Prejudice", 1813, Author("Jane Austen")))
    )

  // server-side logic
  implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global
  implicit val contextShift: ContextShift[IO] = IO.contextShift(ec)
  implicit val timer: Timer[IO] = IO.timer(ec)

  val books = new AtomicReference(
    Vector(
      Book("The Sorrows of Young Werther", 1774, Author("Johann Wolfgang von Goethe")),
      Book("Iliad", -8000, Author("Homer")),
      Book("Nad Niemnem", 1888, Author("Eliza Orzeszkowa")),
      Book("The Colour of Magic", 1983, Author("Terry Pratchett")),
      Book("The Art of Computer Programming", 1968, Author("Donald Knuth")),
      Book("Pharaoh", 1897, Author("Boleslaw Prus"))
    )
  )

  val booksListingRoutes: HttpRoutes[IO] = booksListing.toRoutes(_ => IO(books.get().asRight[Unit]))
  @silent("discarded")
  val addBookRoutes: HttpRoutes[IO] = addBook.toRoutes(book => IO((books.getAndUpdate(books => books :+ book): Unit).asRight[Unit]))
  val routes: HttpRoutes[IO] = booksListingRoutes <+> addBookRoutes

  // generating the documentation in yml; extension methods come from imported packages
  val openApiDocs: OpenAPI = List(booksListing, addBook).toOpenAPI("The tapir library", "1.0.0")
  val openApiYml: String = openApiDocs.toYaml

  // starting the server
  BlazeServerBuilder[IO](ec)
    .bindHttp(8080, "localhost")
    .withHttpApp(Router("/" -> (routes <+> new SwaggerHttp4s(openApiYml).routes[IO])).orNotFound)
    .resource
    .use { _ =>
      IO {
        println("Go to: http://localhost:8080/docs")
        println("Press any key to exit ...")
        scala.io.StdIn.readLine()
      }
    }
    .unsafeRunSync()
} 
Example 3
Source File: FederatedApp.scala    From caliban   with Apache License 2.0 5 votes vote down vote up
package caliban.federation

import caliban.Http4sAdapter
import caliban.federation.FederationData.characters.sampleCharacters
import caliban.federation.FederationData.episodes.sampleEpisodes
import cats.data.Kleisli
import cats.effect.Blocker
import org.http4s.StaticFile
import org.http4s.implicits._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.server.middleware.CORS
import zio._
import zio.blocking.Blocking
import zio.interop.catz._

import scala.concurrent.ExecutionContext

object FederatedApp extends CatsApp {
  type ExampleTask[A] = RIO[ZEnv, A]

  val service1 = CharacterService
    .make(sampleCharacters)
    .memoize
    .use(layer =>
      for {
        blocker     <- ZIO.access[Blocking](_.get.blockingExecutor.asEC).map(Blocker.liftExecutionContext)
        interpreter <- FederatedApi.Characters.api.interpreter.map(_.provideCustomLayer(layer))
        _ <- BlazeServerBuilder[ExampleTask](ExecutionContext.global)
              .bindHttp(8089, "localhost")
              .withHttpApp(
                Router[ExampleTask](
                  "/api/graphql" -> CORS(Http4sAdapter.makeHttpService(interpreter)),
                  "/graphiql"    -> Kleisli.liftF(StaticFile.fromResource("/graphiql.html", blocker, None))
                ).orNotFound
              )
              .resource
              .toManaged
              .useForever
      } yield ()
    )

  val service2 = EpisodeService
    .make(sampleEpisodes)
    .memoize
    .use(layer =>
      for {
        blocker     <- ZIO.access[Blocking](_.get.blockingExecutor.asEC).map(Blocker.liftExecutionContext)
        interpreter <- FederatedApi.Episodes.api.interpreter.map(_.provideCustomLayer(layer))
        _ <- BlazeServerBuilder[ExampleTask](ExecutionContext.global)
              .bindHttp(8088, "localhost")
              .withHttpApp(
                Router[ExampleTask](
                  "/api/graphql" -> CORS(Http4sAdapter.makeHttpService(interpreter)),
                  "/graphiql"    -> Kleisli.liftF(StaticFile.fromResource("/graphiql.html", blocker, None))
                ).orNotFound
              )
              .resource
              .toManaged
              .useForever
      } yield ()
    )

  override def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] =
    (service1 race service2).exitCode
} 
Example 4
Source File: Main.scala    From pfps-shopping-cart   with Apache License 2.0 5 votes vote down vote up
package shop

import cats.effect._
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import org.http4s.server.blaze.BlazeServerBuilder
import shop.modules._

object Main extends IOApp {

  implicit val logger = Slf4jLogger.getLogger[IO]

  override def run(args: List[String]): IO[ExitCode] =
    config.load[IO].flatMap { cfg =>
      Logger[IO].info(s"Loaded config $cfg") >>
        AppResources.make[IO](cfg).use { res =>
          for {
            security <- Security.make[IO](cfg, res.psql, res.redis)
            algebras <- Algebras.make[IO](res.redis, res.psql, cfg.cartExpiration)
            clients <- HttpClients.make[IO](cfg.paymentConfig, res.client)
            programs <- Programs.make[IO](cfg.checkoutConfig, algebras, clients)
            api <- HttpApi.make[IO](algebras, programs, security)
            _ <- BlazeServerBuilder[IO]
                  .bindHttp(
                    cfg.httpServerConfig.port.value,
                    cfg.httpServerConfig.host.value
                  )
                  .withHttpApp(api.httpApp)
                  .serve
                  .compile
                  .drain
          } yield ExitCode.Success
        }
    }

} 
Example 5
Source File: BackendServer.scala    From zio-telemetry   with Apache License 2.0 5 votes vote down vote up
package zio.telemetry.opentracing.example

import cats.effect.{ ExitCode => catsExitCode }
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._
import zio.interop.catz._
import zio.telemetry.opentracing.example.JaegerTracer.makeService
import zio.telemetry.opentracing.example.config.Configuration
import zio.telemetry.opentracing.example.http.{ AppTask, StatusService }
import zio.{ ExitCode, ZEnv, ZIO }

object BackendServer extends CatsApp {

  override def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] =
    (for {
      conf    <- Configuration.load.provideLayer(Configuration.live)
      service = makeService(conf.tracer.host, "zio-backend")
      router  = Router[AppTask]("/" -> StatusService.status(service)).orNotFound
      result <- BlazeServerBuilder[AppTask]
                 .bindHttp(conf.backend.port, conf.backend.host)
                 .withHttpApp(router)
                 .serve
                 .compile[AppTask, AppTask, catsExitCode]
                 .drain
                 .as(ExitCode.success)
    } yield result).orElse(ZIO.succeed(ExitCode.failure))
} 
Example 6
Source File: ProxyServer.scala    From zio-telemetry   with Apache License 2.0 5 votes vote down vote up
package zio.telemetry.opentracing.example

import cats.effect.{ ExitCode => catsExitCode }
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._
import sttp.model.Uri
import zio.interop.catz._
import zio.telemetry.opentracing.example.JaegerTracer.makeService
import zio.telemetry.opentracing.example.config.Configuration
import zio.telemetry.opentracing.example.http.{ AppTask, StatusesService }
import zio.{ ExitCode, ZEnv, ZIO }

object ProxyServer extends CatsApp {

  override def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] =
    (for {
      conf       <- Configuration.load.provideLayer(Configuration.live)
      service    = makeService(conf.tracer.host, "zio-proxy")
      backendUrl <- ZIO.fromEither(Uri.safeApply(conf.backend.host, conf.backend.port))
      router     = Router[AppTask]("/" -> StatusesService.statuses(backendUrl, service)).orNotFound
      result <- BlazeServerBuilder[AppTask]
                 .bindHttp(conf.proxy.port, conf.proxy.host)
                 .withHttpApp(router)
                 .serve
                 .compile[AppTask, AppTask, catsExitCode]
                 .drain
                 .as(ExitCode.success)
    } yield result) orElse ZIO.succeed(ExitCode.failure)

} 
Example 7
Source File: BackendServer.scala    From zio-telemetry   with Apache License 2.0 5 votes vote down vote up
package zio.telemetry.opentelemetry.example

import org.http4s.server.{ Router, _ }
import org.http4s.server.blaze.BlazeServerBuilder
import zio.clock.Clock
import zio.interop.catz._
import zio.telemetry.opentelemetry.Tracing
import zio.telemetry.opentelemetry.example.config.{ Config, Configuration }
import zio.telemetry.opentelemetry.example.http.{ AppEnv, AppTask, Client, StatusService }
import zio.{ ExitCode, Managed, ZIO, ZLayer }
import org.http4s.syntax.kleisli._
import sttp.client.asynchttpclient.zio.AsyncHttpClientZioBackend

object BackendServer extends zio.App {
  val router = Router[AppTask]("/" -> StatusService.routes).orNotFound

  val server =
    ZIO
      .runtime[AppEnv]
      .flatMap(implicit runtime =>
        BlazeServerBuilder[AppTask]
          .bindHttp(
            runtime.environment.get[Config].backend.host.port.getOrElse(defaults.HttpPort),
            runtime.environment.get[Config].backend.host.host
          )
          .withHttpApp(router)
          .serve
          .compile
          .drain
      )

  val httpBackend = ZLayer.fromManaged(Managed.make(AsyncHttpClientZioBackend())(_.close.ignore))
  val client      = Configuration.live ++ httpBackend >>> Client.live
  val tracer      = Configuration.live >>> JaegerTracer.live("zio-backend")
  val envLayer    = tracer ++ Clock.live >>> Tracing.live ++ Configuration.live ++ client

  override def run(args: List[String]) =
    server.provideCustomLayer(envLayer).fold(_ => ExitCode.failure, _ => ExitCode.success)
} 
Example 8
Source File: ProxyServer.scala    From zio-telemetry   with Apache License 2.0 5 votes vote down vote up
package zio.telemetry.opentelemetry.example

import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.server.{ defaults, Router }
import zio.clock.Clock
import zio.interop.catz._
import zio.telemetry.opentelemetry.Tracing
import zio.telemetry.opentelemetry.example.config.{ Config, Configuration }
import zio.telemetry.opentelemetry.example.http.{ AppEnv, AppTask, Client, StatusesService }
import zio.{ ExitCode, Managed, ZIO, ZLayer }
import org.http4s.syntax.kleisli._
import sttp.client.asynchttpclient.zio.AsyncHttpClientZioBackend

object ProxyServer extends zio.App {

  val router = Router[AppTask]("/" -> StatusesService.routes).orNotFound

  val server =
    ZIO
      .runtime[AppEnv]
      .flatMap(implicit runtime =>
        BlazeServerBuilder[AppTask]
          .bindHttp(
            runtime.environment.get[Config].proxy.host.port.getOrElse(defaults.HttpPort),
            runtime.environment.get[Config].proxy.host.host
          )
          .withHttpApp(router)
          .serve
          .compile
          .drain
      )

  val httpBackend = ZLayer.fromManaged(Managed.make(AsyncHttpClientZioBackend())(_.close.ignore))
  val client      = Configuration.live ++ httpBackend >>> Client.live
  val tracer      = Configuration.live >>> JaegerTracer.live("zio-proxy")
  val envLayer    = tracer ++ Clock.live >>> Tracing.live ++ Configuration.live ++ client

  override def run(args: List[String]) =
    server.provideCustomLayer(envLayer).fold(_ => ExitCode.failure, _ => ExitCode.success)
} 
Example 9
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 10
Source File: ExampleApp.scala    From caliban   with Apache License 2.0 5 votes vote down vote up
package caliban.tapir

import caliban.interop.tapir._
import caliban.tapir.Endpoints._
import caliban.{ GraphQL, Http4sAdapter }
import cats.data.Kleisli
import cats.effect.Blocker
import org.http4s.StaticFile
import org.http4s.implicits._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.server.middleware.CORS
import sttp.tapir.server.ServerEndpoint
import zio._
import zio.blocking.Blocking
import zio.interop.catz._
import zio.interop.catz.implicits._

import scala.concurrent.ExecutionContext

object ExampleApp extends CatsApp {

  // approach 1: using `Endpoint` and providing the logic
  val graphql: GraphQL[Any] =
    addBook.toGraphQL((bookAddLogic _).tupled) |+|
      deleteBook.toGraphQL((bookDeleteLogic _).tupled) |+|
      booksListing.toGraphQL((bookListingLogic _).tupled)

  // approach 2: using the `ServerEndpoint` where logic is already provided
  type MyIO[+A] = IO[String, A]

  val addBookEndpoint: ServerEndpoint[(Book, String), String, Unit, Nothing, MyIO] =
    addBook.serverLogic[MyIO] { case (book, token) => bookAddLogic(book, token).either }
  val deleteBookEndpoint: ServerEndpoint[(String, String), String, Unit, Nothing, MyIO] =
    deleteBook.serverLogic[MyIO] { case (title, token) => bookDeleteLogic(title, token).either }
  val booksListingEndpoint: ServerEndpoint[(Option[Int], Option[Int]), Nothing, List[Book], Nothing, UIO] =
    booksListing.serverLogic[UIO] { case (year, limit) => bookListingLogic(year, limit).map(Right(_)) }

  val graphql2: GraphQL[Any] =
    addBookEndpoint.toGraphQL |+| deleteBookEndpoint.toGraphQL |+| booksListingEndpoint.toGraphQL

  override def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] =
    (for {
      blocker     <- ZIO.access[Blocking](_.get.blockingExecutor.asEC).map(Blocker.liftExecutionContext)
      interpreter <- graphql.interpreter
      _ <- BlazeServerBuilder[Task](ExecutionContext.global)
            .bindHttp(8088, "localhost")
            .withHttpApp(
              Router[Task](
                "/api/graphql" -> CORS(Http4sAdapter.makeHttpService(interpreter)),
                "/graphiql"    -> Kleisli.liftF(StaticFile.fromResource("/graphiql.html", blocker, None))
              ).orNotFound
            )
            .resource
            .toManaged
            .useForever
    } yield ()).exitCode
} 
Example 11
Source File: StreamingHttp4sFs2Server.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.examples

import java.nio.charset.StandardCharsets

import cats.effect._
import cats.implicits._
import org.http4s.HttpRoutes
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._
import sttp.client._
import sttp.tapir._
import sttp.tapir.server.http4s._
import fs2._
import sttp.model.HeaderNames

import scala.concurrent.ExecutionContext
import scala.concurrent.duration._

// https://github.com/softwaremill/tapir/issues/367
object StreamingHttp4sFs2Server extends App {
  // corresponds to: GET /receive?name=...
  // We need to provide both the schema of the value (for documentation), as well as the format (media type) of the
  // body. Here, the schema is a `string` and the media type is `text/plain`.
  val streamingEndpoint = endpoint.get
    .in("receive")
    .out(header[Long](HeaderNames.ContentLength))
    .out(streamBody[Stream[IO, Byte]](schemaFor[String], CodecFormat.TextPlain(), Some(StandardCharsets.UTF_8)))

  // mandatory implicits
  implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global
  implicit val contextShift: ContextShift[IO] = IO.contextShift(ec)
  implicit val timer: Timer[IO] = IO.timer(ec)

  // converting an endpoint to a route (providing server-side logic); extension method comes from imported packages
  val streamingRoutes: HttpRoutes[IO] = streamingEndpoint.toRoutes { _ =>
    val size = 100L
    Stream
      .emit(List[Char]('a', 'b', 'c', 'd'))
      .repeat
      .flatMap(list => Stream.chunk(Chunk.seq(list)))
      .metered[IO](100.millis)
      .take(size)
      .covary[IO]
      .map(_.toByte)
      .pure[IO]
      .map(s => Right((size, s)))
  }

  // starting the server
  BlazeServerBuilder[IO](ec)
    .bindHttp(8080, "localhost")
    .withHttpApp(Router("/" -> streamingRoutes).orNotFound)
    .resource
    .use { _ =>
      IO {
        implicit val backend: SttpBackend[Identity, Nothing, NothingT] = HttpURLConnectionBackend()
        val result: String = basicRequest.response(asStringAlways).get(uri"http://localhost:8080/receive").send().body
        println("Got result: " + result)

        assert(result == "abcd" * 25)
      }
    }
    .unsafeRunSync()
} 
Example 12
Source File: HelloWorldHttp4sServer.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.examples

import cats.effect._
import sttp.client._
import org.http4s.HttpRoutes
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._
import sttp.tapir._
import sttp.tapir.server.http4s._
import cats.implicits._

import scala.concurrent.ExecutionContext

object HelloWorldHttp4sServer extends App {
  // the endpoint: single fixed path input ("hello"), single query parameter
  // corresponds to: GET /hello?name=...
  val helloWorld: Endpoint[String, Unit, String, Nothing] =
    endpoint.get.in("hello").in(query[String]("name")).out(stringBody)

  // mandatory implicits
  implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global
  implicit val contextShift: ContextShift[IO] = IO.contextShift(ec)
  implicit val timer: Timer[IO] = IO.timer(ec)

  // converting an endpoint to a route (providing server-side logic); extension method comes from imported packages
  val helloWorldRoutes: HttpRoutes[IO] = helloWorld.toRoutes(name => IO(s"Hello, $name!".asRight[Unit]))

  // starting the server

  BlazeServerBuilder[IO](ec)
    .bindHttp(8080, "localhost")
    .withHttpApp(Router("/" -> helloWorldRoutes).orNotFound)
    .resource
    .use { _ =>
      IO {
        implicit val backend: SttpBackend[Identity, Nothing, NothingT] = HttpURLConnectionBackend()
        val result: String = basicRequest.response(asStringAlways).get(uri"http://localhost:8080/hello?name=Frodo").send().body
        println("Got result: " + result)

        assert(result == "Hello, Frodo!")
      }
    }
    .unsafeRunSync()
} 
Example 13
Source File: ZioExampleHttp4sServer.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.examples

import org.http4s._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._
import zio.interop.catz._
import zio.interop.catz.implicits._
import zio.{Has, IO, Runtime, Task, UIO, ZIO, ZLayer, ZEnv}
import sttp.tapir.ztapir._
import sttp.tapir.server.http4s.ztapir._
import sttp.tapir.swagger.http4s.SwaggerHttp4s
import cats.implicits._
import UserLayer.UserService
import sttp.tapir.examples.ZioExampleHttp4sServer.Pet
import zio.console.Console

object ZioExampleHttp4sServer extends App {
  case class Pet(species: String, url: String)

  import io.circe.generic.auto._
  import sttp.tapir.json.circe._

  // Sample endpoint, with the logic implemented directly using .toRoutes
  val petEndpoint: ZEndpoint[Int, String, Pet] =
    endpoint.get.in("pet" / path[Int]("petId")).errorOut(stringBody).out(jsonBody[Pet])

  val petRoutes: HttpRoutes[Task] = petEndpoint.toRoutes { petId =>
    if (petId == 35) {
      UIO(Pet("Tapirus terrestris", "https://en.wikipedia.org/wiki/Tapir"))
    } else {
      IO.fail("Unknown pet id")
    }
  }

  // Same endpoint as above, but using a custom application layer
  val pet2Endpoint: ZEndpoint[Int, String, Pet] =
    endpoint.get.in("pet2" / path[Int]("petId")).errorOut(stringBody).out(jsonBody[Pet])

  val pet2Routes: HttpRoutes[Task] = pet2Endpoint.toRoutes(petId => UserService.hello(petId).provideLayer(UserLayer.liveEnv))

  // Final service is just a conjunction of different Routes
  implicit val runtime: Runtime[ZEnv] = Runtime.default
  val service: HttpRoutes[Task] = petRoutes <+> pet2Routes

  //
  // Same as above, but combining endpoint description with server logic:
  //

  val petServerEndpoint = petEndpoint.zServerLogic { petId =>
    if (petId == 35) {
      UIO(Pet("Tapirus terrestris", "https://en.wikipedia.org/wiki/Tapir"))
    } else {
      IO.fail("Unknown pet id")
    }
  }
  val petServerRoutes: HttpRoutes[Task] = petServerEndpoint.toRoutes

  val pet2ServerEndpoint = pet2Endpoint.zServerLogic { petId => UserService.hello(petId).provideLayer(UserLayer.liveEnv) }
  val pet2ServerRoutes: HttpRoutes[Task] = petServerEndpoint.toRoutes

  import sttp.tapir.docs.openapi._
  import sttp.tapir.openapi.circe.yaml._
  val yaml = List(petEndpoint).toOpenAPI("Our pets", "1.0").toYaml

  val serve = BlazeServerBuilder[Task](runtime.platform.executor.asEC)
    .bindHttp(8080, "localhost")
    .withHttpApp(Router("/" -> (service <+> new SwaggerHttp4s(yaml).routes[Task])).orNotFound)
    .serve
    .compile
    .drain

  runtime.unsafeRun(serve)
}

object UserLayer {
  type UserService = Has[UserService.Service]

  object UserService {
    trait Service {
      def hello(id: Int): ZIO[Any, String, Pet]
    }

    val live: ZLayer[Console, Nothing, Has[Service]] = ZLayer.fromFunction { console: Console => (id: Int) =>
      {
        console.get.putStrLn(s"Got Pet request for $id") >>
          ZIO.succeed(Pet(id.toString, "https://zio.dev"))
      }
    }

    def hello(id: Int): ZIO[UserService, String, Pet] = ZIO.accessM(_.get.hello(id))
  }

  val liveEnv: ZLayer[Any, Nothing, Has[UserService.Service]] = Console.live >>> UserService.live
} 
Example 14
Source File: Http4sServerTests.scala    From tapir   with Apache License 2.0 5 votes vote down vote up
package sttp.tapir.server.http4s

import cats.data.{Kleisli, NonEmptyList}
import cats.effect._
import cats.implicits._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._
import org.http4s.{EntityBody, HttpRoutes, Request, Response}
import sttp.tapir.server.tests.ServerTests
import sttp.tapir.Endpoint
import sttp.tapir._
import sttp.client._
import sttp.tapir.server.{DecodeFailureHandler, ServerDefaults, ServerEndpoint}
import sttp.tapir.tests.{Port, PortCounter}

import scala.concurrent.ExecutionContext
import scala.reflect.ClassTag

class Http4sServerTests extends ServerTests[IO, EntityBody[IO], HttpRoutes[IO]] {
  implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global
  implicit val contextShift: ContextShift[IO] = IO.contextShift(ec)
  implicit val timer: Timer[IO] = IO.timer(ec)

  override def pureResult[T](t: T): IO[T] = IO.pure(t)
  override def suspendResult[T](t: => T): IO[T] = IO.apply(t)

  override def route[I, E, O](
      e: ServerEndpoint[I, E, O, EntityBody[IO], IO],
      decodeFailureHandler: Option[DecodeFailureHandler] = None
  ): HttpRoutes[IO] = {
    implicit val serverOptions: Http4sServerOptions[IO] = Http4sServerOptions
      .default[IO]
      .copy(
        decodeFailureHandler = decodeFailureHandler.getOrElse(ServerDefaults.decodeFailureHandler)
      )
    e.toRoutes
  }

  override def routeRecoverErrors[I, E <: Throwable, O](e: Endpoint[I, E, O, EntityBody[IO]], fn: I => IO[O])(implicit
      eClassTag: ClassTag[E]
  ): HttpRoutes[IO] = {
    e.toRouteRecoverErrors(fn)
  }

  override def server(routes: NonEmptyList[HttpRoutes[IO]], port: Port): Resource[IO, Unit] = {
    val service: Kleisli[IO, Request[IO], Response[IO]] = routes.reduceK.orNotFound

    BlazeServerBuilder[IO](ExecutionContext.global)
      .bindHttp(port, "localhost")
      .withHttpApp(service)
      .resource
      .void
  }

  override lazy val portCounter: PortCounter = new PortCounter(56000)

  if (testNameFilter.isEmpty) {
    test("should work with a router and routes in a context") {
      val e = endpoint.get.in("test" / "router").out(stringBody).serverLogic(_ => IO.pure("ok".asRight[Unit]))
      val routes = e.toRoutes
      val port = portCounter.next()

      BlazeServerBuilder[IO](ExecutionContext.global)
        .bindHttp(port, "localhost")
        .withHttpApp(Router("/api" -> routes).orNotFound)
        .resource
        .use { _ => basicRequest.get(uri"http://localhost:$port/api/test/router").send().map(_.body shouldBe Right("ok")) }
        .unsafeRunSync()
    }
  }
} 
Example 15
Source File: InvoicesServer.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.{ExitCode, IO, IOApp}
import cats.syntax.functor._
import fs2.Stream
import fs2.concurrent.Topic
import org.amitayh.invoices.common.Config.Topics
import org.amitayh.invoices.common.domain.{Command, CommandResult, InvoiceSnapshot}
import org.amitayh.invoices.dao.{InvoiceList, MySqlInvoiceList}
import org.amitayh.invoices.web.PushEvents._
import org.http4s.implicits._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder

object InvoicesServer extends IOApp {

  override def run(args: List[String]): IO[ExitCode] =
    stream.compile.drain.as(ExitCode.Success)

  private val stream: Stream[IO, ExitCode] = for {
    invoiceList <- Stream.resource(MySqlInvoiceList.resource[IO])
    producer <- Stream.resource(Kafka.producer[IO, UUID, Command](Topics.Commands))
    commandResultsTopic <- Stream.eval(Topic[IO, CommandResultRecord](None))
    invoiceUpdatesTopic <- Stream.eval(Topic[IO, InvoiceSnapshotRecord](None))
    server <- httpServer(invoiceList, producer, commandResultsTopic, invoiceUpdatesTopic) concurrently
      commandResults.through(commandResultsTopic.publish) concurrently
      invoiceUpdates.through(invoiceUpdatesTopic.publish)
  } yield server

  private def commandResults: Stream[IO, CommandResultRecord] =
    Kafka.subscribe[IO, UUID, CommandResult](
      topic = Topics.CommandResults,
      groupId = "invoices.websocket.command-results").map(Some(_))

  private def invoiceUpdates: Stream[IO, InvoiceSnapshotRecord] =
    Kafka.subscribe[IO, UUID, InvoiceSnapshot](
      topic = Topics.Snapshots,
      groupId = "invoices.websocket.snapshots").map(Some(_))

  private def httpServer(invoiceList: InvoiceList[IO],
                         producer: Kafka.Producer[IO, UUID, Command],
                         commandResultsTopic: Topic[IO, CommandResultRecord],
                         invoiceUpdatesTopic: Topic[IO, InvoiceSnapshotRecord]): Stream[IO, ExitCode] =
    BlazeServerBuilder[IO]
      .bindHttp(8080, "0.0.0.0")
      .withHttpApp(
        Router(
          "/api" -> InvoicesApi[IO].service(invoiceList, producer, commandResultsTopic),
          "/events" -> PushEvents[IO].service(commandResultsTopic, invoiceUpdatesTopic),
          "/" -> Statics[IO].service).orNotFound)
      .serve

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

import java.net.{InetSocketAddress, StandardSocketOptions}

import cats.effect.{ConcurrentEffect, Resource, Timer}
import org.http4s.HttpApp
import org.http4s.server.Server
import org.http4s.server.blaze.BlazeServerBuilder

import scala.concurrent.ExecutionContext
import scala.concurrent.duration.Duration

object Http4sBlazeServerModule {

  
  def make[F[_]: ConcurrentEffect: Timer](
      config: Http4sBlazeServerConfig,
      httpApp: HttpApp[F],
      executionContext: ExecutionContext
  ): Resource[F, Server[F]] = {
    for {
      inetSocketAddress <- Resource.liftF(
        ConcurrentEffect[F].delay(
          InetSocketAddress.createUnresolved(config.listenAddress, config.listenPort)
        )
      )
      server <-
        BlazeServerBuilder[F](executionContext)
          .bindSocketAddress(inetSocketAddress)
          .withHttpApp(httpApp)
          .withoutBanner
          .withNio2(config.nio2Enabled)
          .withWebSockets(config.webSocketsEnabled)
          .enableHttp2(config.http2Enabled)
          .withResponseHeaderTimeout(Duration.fromNanos(config.responseHeaderTimeout.toNanos))
          .withIdleTimeout(Duration.fromNanos(config.idleTimeout.toNanos))
          .withBufferSize(config.bufferSize)
          .withMaxRequestLineLength(config.maxRequestLineLength)
          .withMaxHeadersLength(config.maxHeadersLength)
          .withChunkBufferMaxSize(config.chunkBufferMaxSize)
          .withConnectorPoolSize(config.connectorPoolSize)
          .withChannelOption[java.lang.Boolean](StandardSocketOptions.TCP_NODELAY, config.socketOptions.tcpNoDelay)
          .resource
    } yield server
  }
} 
Example 17
Source File: CorrelationIdMiddlewareTest.scala    From scala-server-toolkit   with MIT License 5 votes vote down vote up
package com.avast.sst.http4s.server.middleware

import java.net.InetSocketAddress

import cats.effect.{ContextShift, IO, Resource, Timer}
import com.avast.sst.http4s.server.Http4sRouting
import org.http4s.client.blaze.BlazeClientBuilder
import org.http4s.dsl.Http4sDsl
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.util.CaseInsensitiveString
import org.http4s.{Header, HttpRoutes, Request, Uri}
import org.scalatest.funsuite.AsyncFunSuite

import scala.concurrent.ExecutionContext

@SuppressWarnings(Array("scalafix:Disable.get", "scalafix:Disable.toString", "scalafix:Disable.createUnresolved"))
class CorrelationIdMiddlewareTest extends AsyncFunSuite with Http4sDsl[IO] {

  implicit private val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
  implicit private val timer: Timer[IO] = IO.timer(ExecutionContext.global)

  test("CorrelationIdMiddleware fills Request attributes and HTTP response header") {
    val test = for {
      middleware <- Resource.liftF(CorrelationIdMiddleware.default[IO])
      routes = Http4sRouting.make {
        middleware.wrap {
          HttpRoutes.of[IO] {
            case req @ GET -> Root / "test" =>
              val id = middleware.retrieveCorrelationId(req)
              Ok("test").map(_.withHeaders(Header("Attribute-Value", id.toString)))
          }
        }
      }
      server <- BlazeServerBuilder[IO](ExecutionContext.global)
        .bindSocketAddress(InetSocketAddress.createUnresolved("127.0.0.1", 0))
        .withHttpApp(routes)
        .resource
      client <- BlazeClientBuilder[IO](ExecutionContext.global).resource
    } yield (server, client)

    test
      .use {
        case (server, client) =>
          client
            .run(
              Request[IO](uri = Uri.unsafeFromString(s"http://${server.address.getHostString}:${server.address.getPort}/test"))
                .withHeaders(Header("Correlation-Id", "test-value"))
            )
            .use { response =>
              IO.delay {
                assert(response.headers.get(CaseInsensitiveString("Correlation-Id")).get.value === "test-value")
                assert(response.headers.get(CaseInsensitiveString("Attribute-Value")).get.value === "Some(CorrelationId(test-value))")
              }
            }
      }
      .unsafeToFuture()
  }

} 
Example 18
Source File: Http4sRpcServer.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.network.rpc.http

import cats.effect.{ConcurrentEffect, Resource, Sync, Timer}
import cats.implicits._
import io.circe.Json
import io.circe.syntax._
import jbok.network.rpc.{RpcRequest, RpcService}
import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityCodec._
import org.http4s.dsl.Http4sDsl
import org.http4s.implicits._
import org.http4s.server.Server
import org.http4s.server.blaze.BlazeServerBuilder

object Http4sRpcServer {
  def routes[F[_]](service: RpcService[F, Json])(implicit F: Sync[F]): HttpRoutes[F] = {
    val dsl = Http4sDsl[F]
    import dsl._

    HttpRoutes.of[F] {
      case req @ POST -> path =>
        for {
          json   <- req.as[Json]
          result <- service.handle(RpcRequest(path.toList, json))
          resp   <- Ok(result.asJson)
        } yield resp
    }
  }

  def server[F[_]](service: RpcService[F, Json])(implicit F: ConcurrentEffect[F], T: Timer[F]): Resource[F, Server[F]] =
    BlazeServerBuilder[F]
      .bindLocal(0)
      .withHttpApp(routes[F](service).orNotFound)
      .withWebSockets(true)
      .resource
} 
Example 19
Source File: AuthExampleApp.scala    From caliban   with Apache License 2.0 5 votes vote down vote up
package caliban.http4s

import caliban.GraphQL._
import caliban.schema.GenericSchema
import caliban.{ Http4sAdapter, RootResolver }
import org.http4s.HttpRoutes
import org.http4s.dsl.Http4sDsl
import org.http4s.implicits._
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.server.{ Router, ServiceErrorHandler }
import org.http4s.util.CaseInsensitiveString
import zio._
import zio.interop.catz._
import zio.interop.catz.implicits._

import scala.concurrent.ExecutionContext

object AuthExampleApp extends CatsApp {

  // Simple service that returns the token coming from the request
  type Auth = Has[Auth.Service]
  object Auth {
    trait Service {
      def token: String
    }
  }
  type AuthTask[A] = RIO[Auth, A]

  case class MissingToken() extends Throwable

  // http4s middleware that extracts a token from the request and eliminate the Auth layer dependency
  object AuthMiddleware {
    def apply(route: HttpRoutes[AuthTask]): HttpRoutes[Task] =
      Http4sAdapter.provideLayerFromRequest(
        route,
        _.headers.get(CaseInsensitiveString("token")) match {
          case Some(value) => ZLayer.succeed(new Auth.Service { override def token: String = value.value })
          case None        => ZLayer.fail(MissingToken())
        }
      )
  }

  // http4s error handler to customize the response for our throwable
  object dsl extends Http4sDsl[Task]
  import dsl._
  val errorHandler: ServiceErrorHandler[Task] = _ => { case MissingToken() => Forbidden() }

  // our GraphQL API
  val schema: GenericSchema[Auth] = new GenericSchema[Auth] {}
  import schema._
  case class Query(token: RIO[Auth, String])
  private val resolver = RootResolver(Query(ZIO.access[Auth](_.get[Auth.Service].token)))
  private val api      = graphQL(resolver)

  override def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] =
    (for {
      interpreter <- api.interpreter
      route       = AuthMiddleware(Http4sAdapter.makeHttpService(interpreter))
      _ <- BlazeServerBuilder[Task](ExecutionContext.global)
            .withServiceErrorHandler(errorHandler)
            .bindHttp(8088, "localhost")
            .withHttpApp(Router[Task]("/api/graphql" -> route).orNotFound)
            .resource
            .toManaged
            .useForever
    } yield ()).exitCode
} 
Example 20
Source File: ExampleApp.scala    From caliban   with Apache License 2.0 5 votes vote down vote up
package caliban.http4s

import caliban.ExampleData._
import caliban.ExampleService.ExampleService
import caliban.{ ExampleApi, ExampleService, Http4sAdapter }
import cats.data.Kleisli
import cats.effect.Blocker
import org.http4s.StaticFile
import org.http4s.implicits._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.server.middleware.CORS
import zio._
import zio.blocking.Blocking
import zio.interop.catz._

import scala.concurrent.ExecutionContext

object ExampleApp extends App {

  type ExampleTask[A] = RIO[ZEnv with ExampleService, A]

  override def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] =
    ZIO
      .runtime[ZEnv with ExampleService]
      .flatMap(implicit runtime =>
        for {
          blocker     <- ZIO.access[Blocking](_.get.blockingExecutor.asEC).map(Blocker.liftExecutionContext)
          interpreter <- ExampleApi.api.interpreter
          _ <- BlazeServerBuilder[ExampleTask](ExecutionContext.global)
                .bindHttp(8088, "localhost")
                .withHttpApp(
                  Router[ExampleTask](
                    "/api/graphql" -> CORS(Http4sAdapter.makeHttpService(interpreter)),
                    "/ws/graphql"  -> CORS(Http4sAdapter.makeWebSocketService(interpreter)),
                    "/graphiql"    -> Kleisli.liftF(StaticFile.fromResource("/graphiql.html", blocker, None))
                  ).orNotFound
                )
                .resource
                .toManaged
                .useForever
        } yield ()
      )
      .provideCustomLayer(ExampleService.make(sampleCharacters))
      .exitCode
} 
Example 21
Source File: Server.scala    From scala-pet-store   with Apache License 2.0 5 votes vote down vote up
package io.github.pauljamescleary.petstore

import config._
import domain.users._
import domain.orders._
import domain.pets._
import infrastructure.endpoint._
import infrastructure.repository.doobie.{
  DoobieAuthRepositoryInterpreter,
  DoobieOrderRepositoryInterpreter,
  DoobiePetRepositoryInterpreter,
  DoobieUserRepositoryInterpreter,
}
import cats.effect._
import org.http4s.server.{Router, Server => H4Server}
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.implicits._
import tsec.passwordhashers.jca.BCrypt
import doobie.util.ExecutionContexts
import io.circe.config.parser
import domain.authentication.Auth
import tsec.authentication.SecuredRequestHandler
import tsec.mac.jca.HMACSHA256

object Server extends IOApp {
  def createServer[F[_]: ContextShift: ConcurrentEffect: Timer]: Resource[F, H4Server[F]] =
    for {
      conf <- Resource.liftF(parser.decodePathF[F, PetStoreConfig]("petstore"))
      serverEc <- ExecutionContexts.cachedThreadPool[F]
      connEc <- ExecutionContexts.fixedThreadPool[F](conf.db.connections.poolSize)
      txnEc <- ExecutionContexts.cachedThreadPool[F]
      xa <- DatabaseConfig.dbTransactor(conf.db, connEc, Blocker.liftExecutionContext(txnEc))
      key <- Resource.liftF(HMACSHA256.generateKey[F])
      authRepo = DoobieAuthRepositoryInterpreter[F, HMACSHA256](key, xa)
      petRepo = DoobiePetRepositoryInterpreter[F](xa)
      orderRepo = DoobieOrderRepositoryInterpreter[F](xa)
      userRepo = DoobieUserRepositoryInterpreter[F](xa)
      petValidation = PetValidationInterpreter[F](petRepo)
      petService = PetService[F](petRepo, petValidation)
      userValidation = UserValidationInterpreter[F](userRepo)
      orderService = OrderService[F](orderRepo)
      userService = UserService[F](userRepo, userValidation)
      authenticator = Auth.jwtAuthenticator[F, HMACSHA256](key, authRepo, userRepo)
      routeAuth = SecuredRequestHandler(authenticator)
      httpApp = Router(
        "/users" -> UserEndpoints
          .endpoints[F, BCrypt, HMACSHA256](userService, BCrypt.syncPasswordHasher[F], routeAuth),
        "/pets" -> PetEndpoints.endpoints[F, HMACSHA256](petService, routeAuth),
        "/orders" -> OrderEndpoints.endpoints[F, HMACSHA256](orderService, routeAuth),
      ).orNotFound
      _ <- Resource.liftF(DatabaseConfig.initializeDb(conf.db))
      server <- BlazeServerBuilder[F](serverEc)
        .bindHttp(conf.server.port, conf.server.host)
        .withHttpApp(httpApp)
        .resource
    } yield server

  def run(args: List[String]): IO[ExitCode] = createServer.use(_ => IO.never).as(ExitCode.Success)
} 
Example 22
Source File: ReverseAPI.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.framework.examples.propertyCheck.stringReverse

import com.github.agourlay.cornichon.framework.examples.HttpServer
import monix.eval.Task
import monix.execution.{ CancelableFuture, Scheduler }
import org.http4s._
import org.http4s.implicits._
import org.http4s.dsl._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder

class ReverseAPI extends Http4sDsl[Task] {

  implicit val s = Scheduler.Implicits.global

  object WordQueryParamMatcher extends QueryParamDecoderMatcher[String]("word")

  private val reverseService = HttpRoutes.of[Task] {
    case POST -> Root / "double-reverse" :? WordQueryParamMatcher(word) =>
      Ok(word.reverse.reverse)
  }

  private val routes = Router(
    "/" -> reverseService
  )

  def start(httpPort: Int): CancelableFuture[HttpServer] =
    BlazeServerBuilder[Task](executionContext = s)
      .bindHttp(httpPort, "localhost")
      .withoutBanner
      .withNio2(true)
      .withHttpApp(routes.orNotFound)
      .allocated
      .map { case (_, stop) => new HttpServer(stop) }
      .runToFuture
} 
Example 23
Source File: TurnstileAPI.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.framework.examples.propertyCheck.turnstile

import com.github.agourlay.cornichon.framework.examples.HttpServer
import monix.eval.Task
import monix.execution.atomic.AtomicBoolean
import monix.execution.{ CancelableFuture, Scheduler }
import org.http4s._
import org.http4s.implicits._
import org.http4s.dsl._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder

class TurnstileAPI extends Http4sDsl[Task] {

  implicit val s = Scheduler.Implicits.global

  private val turnstileLocked = AtomicBoolean(true)

  private val turnstileService = HttpRoutes.of[Task] {
    case POST -> Root / "push-coin" =>
      if (turnstileLocked.get()) {
        turnstileLocked.set(false)
        Ok("payment accepted")
      } else
        BadRequest("payment refused")

    case POST -> Root / "walk-through" =>
      if (turnstileLocked.get())
        BadRequest("door blocked")
      else {
        turnstileLocked.set(true)
        Ok("door turns")
      }
  }

  private val routes = Router(
    "/" -> turnstileService
  )

  def start(httpPort: Int): CancelableFuture[HttpServer] =
    BlazeServerBuilder[Task](executionContext = s)
      .bindHttp(httpPort, "localhost")
      .withoutBanner
      .withNio2(true)
      .withHttpApp(routes.orNotFound)
      .allocated
      .map { case (_, stop) => new HttpServer(stop) }
      .runToFuture

} 
Example 24
Source File: EndpointWirings.scala    From ticket-booking-aecor   with Apache License 2.0 5 votes vote down vote up
package ru.pavkin.booking

import cats.effect.{ConcurrentEffect, Timer}
import org.http4s.HttpRoutes
import org.http4s.implicits._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import ru.pavkin.booking.booking.endpoint.{BookingRoutes, DefaultBookingEndpoint}
import ru.pavkin.booking.config.HttpServer

import scala.concurrent.duration.{Duration => _}

final class EndpointWirings[F[_] : ConcurrentEffect : Timer](
  httpServer: HttpServer,
  postgresWirings: PostgresWirings[F],
  entityWirings: EntityWirings[F]) {

  import entityWirings._
  import postgresWirings._

  val bookingsEndpoint = new DefaultBookingEndpoint(bookings, bookingViewRepo)

  val bookingRoutes = new BookingRoutes(bookingsEndpoint)

  val routes: HttpRoutes[F] = bookingRoutes.routes

  def launchHttpService: F[Unit] =
    BlazeServerBuilder[F]
      .bindHttp(httpServer.port, httpServer.interface)
      .withHttpApp(Router("/" -> routes).orNotFound)
      .serve
      .compile
      .drain

} 
Example 25
Source File: Main.scala    From http4s-tracer   with Apache License 2.0 5 votes vote down vote up
package dev.profunktor.tracer

import scala.concurrent.ExecutionContext

import cats.effect._
import cats.implicits._
import cats.Parallel
import dev.profunktor.tracer.module._
import dev.profunktor.tracer.module.tracer._
import dev.profunktor.tracer.Trace.Trace
import org.http4s.client.blaze.BlazeClientBuilder
import org.http4s.server.blaze.BlazeServerBuilder

class Main[F[_]: ConcurrentEffect: Parallel: Timer: Tracer: λ[T[_] => TracerLog[Trace[T, ?]]]] {

  val server: F[Unit] =
    BlazeClientBuilder[F](ExecutionContext.global).resource.use { client =>
      for {
        repos          <- LiveRepositories[F]
        tracedRepos    = TracedRepositories[F](repos)
        tracedClients  = TracedHttpClients[F](client)
        tracedPrograms = TracedPrograms[F](tracedRepos, tracedClients)
        httpApi        = HttpApi[F](tracedPrograms)
        _ <- BlazeServerBuilder
              .apply[F](ExecutionContext.global)
              .bindHttp(8080, "0.0.0.0")
              .withHttpApp(httpApi.httpApp)
              .serve
              .compile
              .drain
      } yield ()
    }

} 
Example 26
Source File: JoexServer.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.joex

import cats.effect._
import cats.effect.concurrent.Ref
import fs2.Stream
import fs2.concurrent.SignallingRef

import docspell.common.Pools
import docspell.joex.routes._

import org.http4s.HttpApp
import org.http4s.implicits._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.server.middleware.Logger

object JoexServer {

  private case class App[F[_]](
      httpApp: HttpApp[F],
      termSig: SignallingRef[F, Boolean],
      exitRef: Ref[F, ExitCode]
  )

  def stream[F[_]: ConcurrentEffect: ContextShift](
      cfg: Config,
      pools: Pools
  )(implicit T: Timer[F]): Stream[F, Nothing] = {

    val app = for {
      signal   <- Resource.liftF(SignallingRef[F, Boolean](false))
      exitCode <- Resource.liftF(Ref[F].of(ExitCode.Success))
      joexApp <-
        JoexAppImpl
          .create[F](cfg, signal, pools.connectEC, pools.httpClientEC, pools.blocker)

      httpApp = Router(
        "/api/info" -> InfoRoutes(),
        "/api/v1"   -> JoexRoutes(joexApp)
      ).orNotFound

      // With Middlewares in place
      finalHttpApp = Logger.httpApp(false, false)(httpApp)

    } yield App(finalHttpApp, signal, exitCode)

    Stream
      .resource(app)
      .flatMap(app =>
        BlazeServerBuilder[F](pools.restEC)
          .bindHttp(cfg.bind.port, cfg.bind.address)
          .withHttpApp(app.httpApp)
          .withoutBanner
          .serveWhile(app.termSig, app.exitRef)
      )

  }.drain
} 
Example 27
Source File: CpgServerMain.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.cpgserver

import cats.effect.{ExitCode, IO, IOApp}
import cats.implicits._
import org.http4s.implicits._
import org.http4s.server.blaze.BlazeServerBuilder

import io.shiftleft.cpgserver.config.ServerConfiguration
import io.shiftleft.cpgserver.cpg.DummyCpgProvider
import io.shiftleft.cpgserver.query.{DefaultAmmoniteExecutor, ServerAmmoniteExecutor}
import io.shiftleft.cpgserver.route.{CpgRoute, HttpErrorHandler, SwaggerRoute}

object CpgServerMain extends IOApp {

  private val banner: String =
    """| ██████╗██████╗  ██████╗     ███████╗███████╗██████╗ ██╗   ██╗███████╗██████╗
       |██╔════╝██╔══██╗██╔════╝     ██╔════╝██╔════╝██╔══██╗██║   ██║██╔════╝██╔══██╗
       |██║     ██████╔╝██║  ███╗    ███████╗█████╗  ██████╔╝██║   ██║█████╗  ██████╔╝
       |██║     ██╔═══╝ ██║   ██║    ╚════██║██╔══╝  ██╔══██╗╚██╗ ██╔╝██╔══╝  ██╔══██╗
       |╚██████╗██║     ╚██████╔╝    ███████║███████╗██║  ██║ ╚████╔╝ ███████╗██║  ██║
       | ╚═════╝╚═╝      ╚═════╝     ╚══════╝╚══════╝╚═╝  ╚═╝  ╚═══╝  ╚══════╝╚═╝  ╚═╝
       |""".stripMargin

  private val cpgProvider: DummyCpgProvider =
    new DummyCpgProvider

  private val ammoniteExecutor: ServerAmmoniteExecutor =
    new DefaultAmmoniteExecutor

  private implicit val httpErrorHandler: HttpErrorHandler =
    CpgRoute.CpgHttpErrorHandler

  private val serverConfig: ServerConfiguration =
    ServerConfiguration.config.getOrElse(ServerConfiguration.default)

  private val httpRoutes =
    CpgRoute(cpgProvider, ammoniteExecutor, serverConfig.files).routes <+> SwaggerRoute().routes

  override def run(args: List[String]): IO[ExitCode] = {
    BlazeServerBuilder[IO]
      .withBanner(List(banner))
      .bindHttp(serverConfig.port, serverConfig.host)
      .withHttpApp(httpRoutes.orNotFound)
      .serve
      .compile
      .drain
      .as(ExitCode.Success)
  }
} 
Example 28
Source File: ServerInterpreterTest.scala    From endpoints4s   with MIT License 5 votes vote down vote up
package endpoints4s.http4s.server

import java.net.ServerSocket

import cats.effect.{ContextShift, IO, Timer}
import endpoints4s.{Invalid, Valid}
import endpoints4s.algebra.server.{
  BasicAuthenticationTestSuite,
  DecodedUrl,
  EndpointsTestSuite,
  JsonEntitiesFromSchemasTestSuite,
  SumTypedEntitiesTestSuite,
  TextEntitiesTestSuite
}
import org.http4s.server.Router
import org.http4s.{HttpRoutes, Uri}
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._

import scala.concurrent.ExecutionContext

class ServerInterpreterTest
    extends EndpointsTestSuite[EndpointsTestApi]
    with BasicAuthenticationTestSuite[EndpointsTestApi]
    with JsonEntitiesFromSchemasTestSuite[EndpointsTestApi]
    with TextEntitiesTestSuite[EndpointsTestApi]
    with SumTypedEntitiesTestSuite[EndpointsTestApi] {

  val serverApi = new EndpointsTestApi()

  def decodeUrl[A](url: serverApi.Url[A])(rawValue: String): DecodedUrl[A] = {
    val uri =
      Uri.fromString(rawValue).getOrElse(sys.error(s"Illegal URI: $rawValue"))

    url.decodeUrl(uri) match {
      case None                  => DecodedUrl.NotMatched
      case Some(Invalid(errors)) => DecodedUrl.Malformed(errors)
      case Some(Valid(a))        => DecodedUrl.Matched(a)
    }
  }

  private def serveGeneralEndpoint[Req, Resp](
      endpoint: serverApi.Endpoint[Req, Resp],
      request2response: Req => Resp
  )(runTests: Int => Unit): Unit = {
    val port = {
      val socket = new ServerSocket(0)
      try socket.getLocalPort
      finally if (socket != null) socket.close()
    }
    implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
    implicit val timer: Timer[IO] = IO.timer(ExecutionContext.global)
    val service = HttpRoutes.of[IO](endpoint.implementedBy(request2response))
    val httpApp = Router("/" -> service).orNotFound
    val server =
      BlazeServerBuilder[IO](ExecutionContext.global)
        .bindHttp(port, "localhost")
        .withHttpApp(httpApp)
    server.resource.use(_ => IO(runTests(port))).unsafeRunSync()
  }

  def serveEndpoint[Resp](
      endpoint: serverApi.Endpoint[_, Resp],
      response: => Resp
  )(runTests: Int => Unit): Unit =
    serveGeneralEndpoint(endpoint, (_: Any) => response)(runTests)

  def serveIdentityEndpoint[Resp](
      endpoint: serverApi.Endpoint[Resp, Resp]
  )(runTests: Int => Unit): Unit =
    serveGeneralEndpoint(endpoint, identity[Resp])(runTests)
} 
Example 29
Source File: Hook.scala    From canoe   with MIT License 5 votes vote down vote up
package canoe.api.sources

import canoe.api.{TelegramClient}
import canoe.methods.webhooks.{DeleteWebhook, SetWebhook}
import canoe.models.{InputFile, Update}
import canoe.syntax.methodOps
import cats.Monad
import cats.effect.{ConcurrentEffect, Resource, Timer}
import cats.syntax.all._
import fs2.Stream
import fs2.concurrent.Queue
import io.chrisdavenport.log4cats.Logger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import org.http4s._
import org.http4s.circe.jsonOf
import org.http4s.dsl.Http4sDsl
import org.http4s.implicits._
import org.http4s.server.Server
import org.http4s.server.blaze.BlazeServerBuilder

class Hook[F[_]](queue: Queue[F, Update]) {
  def updates: Stream[F, Update] = queue.dequeue
}

object Hook {

  
  private def listenServer[F[_]: ConcurrentEffect: Timer: Logger](port: Int): Resource[F, Hook[F]] = {
    val dsl = Http4sDsl[F]
    import dsl._

    def app(queue: Queue[F, Update]): HttpApp[F] =
      HttpRoutes
        .of[F] {
          case req @ POST -> Root =>
            req
              .decodeWith(jsonOf[F, Update], strict = true)(queue.enqueue1(_) *> Ok())
              .recoverWith {
                case InvalidMessageBodyFailure(details, _) =>
                  F.error(s"Received unknown type of update. $details") *> Ok()
              }
        }
        .orNotFound

    def server(queue: Queue[F, Update]): Resource[F, Server[F]] =
      BlazeServerBuilder[F].bindHttp(port).withHttpApp(app(queue)).resource

    Resource.suspend(Queue.unbounded[F, Update].map(q => server(q).map(_ => new Hook[F](q))))
  }
} 
Example 30
Source File: HttpMetricsSpec.scala    From kamon-http4s   with Apache License 2.0 5 votes vote down vote up
package kamon.http4s

import cats.effect._
import kamon.testkit.InstrumentInspection
import org.http4s.HttpRoutes
import org.http4s.dsl.io._
import org.http4s.server.Server
import org.http4s.server.blaze.BlazeServerBuilder
import org.scalatest.concurrent.Eventually
import org.scalatest.time.SpanSugar
import org.scalatest.{Matchers, OptionValues, WordSpec}
import cats.implicits._
import kamon.http4s.middleware.server.KamonSupport
import kamon.instrumentation.http.HttpServerMetrics
import org.http4s.client.blaze.BlazeClientBuilder
import org.http4s.client.Client

import scala.concurrent.ExecutionContext
import org.http4s.implicits._

class HttpMetricsSpec extends WordSpec
  with Matchers
  with Eventually
  with SpanSugar
  with InstrumentInspection.Syntax
  with OptionValues
 {

  implicit val contextShift: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
  implicit val timer: Timer[IO] = IO.timer(ExecutionContext.global)

  val srv =
    BlazeServerBuilder[IO]
      .bindLocal(43567)
      .withHttpApp(KamonSupport(HttpRoutes.of[IO] {
        case GET -> Root / "tracing" / "ok" =>  Ok("ok")
        case GET -> Root / "tracing" / "not-found"  => NotFound("not-found")
        case GET -> Root / "tracing" / "error"  => InternalServerError("This page will generate an error!")
      }, "/127.0.0.1", 43567).orNotFound)
      .resource

  val client =
    BlazeClientBuilder[IO](ExecutionContext.global).withMaxTotalConnections(10).resource

   val metrics =
    Resource.liftF(IO(HttpServerMetrics.of("http4s.server", "/127.0.0.1", 43567)))


  def withServerAndClient[A](f: (Server[IO], Client[IO], HttpServerMetrics.HttpServerInstruments) => IO[A]): A =
   (srv, client, metrics).tupled.use(f.tupled).unsafeRunSync()

  private def get[F[_]: ConcurrentEffect](path: String)(server: Server[F], client: Client[F]): F[String] = {
    client.expect[String](s"http://127.0.0.1:${server.address.getPort}$path")
  }

  "The HttpMetrics" should {

    "track the total of active requests" in withServerAndClient { (server, client, serverMetrics) =>

      val requests = List
        .fill(100) {
          get("/tracing/ok")(server, client)
        }.parSequence_

      val test = IO {
        serverMetrics.activeRequests.distribution().max should be > 1L
        serverMetrics.activeRequests.distribution().min shouldBe 0L
      }
      requests *> test
    }

    "track the response time with status code 2xx" in withServerAndClient { (server, client, serverMetrics) =>
      val requests: IO[Unit] = List.fill(100)(get("/tracing/ok")(server, client)).sequence_

      val test = IO(serverMetrics.requestsSuccessful.value should be >= 0L)

      requests *> test
    }

    "track the response time with status code 4xx" in withServerAndClient { (server, client, serverMetrics) =>
      val requests: IO[Unit] = List.fill(100)(get("/tracing/not-found")(server, client).attempt).sequence_

      val test = IO(serverMetrics.requestsClientError.value should be >= 0L)

      requests *> test
    }

    "track the response time with status code 5xx" in withServerAndClient { (server, client, serverMetrics) =>
      val requests: IO[Unit] = List.fill(100)(get("/tracing/error")(server, client).attempt).sequence_

      val test = IO(serverMetrics.requestsServerError.value should be >= 0L)

      requests *> test
    }
  }
} 
Example 31
Source File: main.scala    From seals   with Apache License 2.0 5 votes vote down vote up
package com.example.messaging

import scala.concurrent.ExecutionContext.Implicits.global

import cats.implicits._
import cats.effect.{ IO, IOApp, ExitCode }

import org.http4s._
import org.http4s.dsl.io._
import org.http4s.client.Client
import org.http4s.circe._
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.server.Router
import org.http4s.implicits._

import dev.tauri.seals._
import dev.tauri.seals.circe.Codecs._

object Protocol {
  final case class Ping(seqNr: Long, payload: Vector[Int])
  final case class Pong(seqNr: Long)
  final case class PingIncompatible(seqNr: Long, payload: Vector[Int], flags: Int)
}

object MyClient extends IOApp {

  import org.http4s.client.blaze._
  import Protocol._

  override def run(args: List[String]): IO[ExitCode] = {
    BlazeClientBuilder[IO](global).resource.use { client =>
      for {
        pongGood <- ping(client, jsonEncoderOf[IO, Envelope[Ping]].toEntity(
          Envelope(Ping(42L, Vector(1, 2, 3, 4)))
        ))
        _ <- IO { assert(pongGood == Pong(42L)) }
        _ <- IO { println(pongGood) }
        pongBad <- ping(client, jsonEncoderOf[IO, Envelope[PingIncompatible]].toEntity(
          Envelope(PingIncompatible(99L, Vector(4, 5), 0))
        ))
        _ <- IO { println(pongBad) }
      } yield ExitCode.Success
    }
  }

  def ping(client: Client[IO], ping: Entity[IO]): IO[Pong] = {
    for {
      pong <- client
        .expect(Request(
          POST,
          Uri(authority = Some(Uri.Authority(port = Some(1234))), path = "/test"),
          body = ping.body
        ))(jsonOf[IO, Envelope[Pong]])
    } yield pong.value
  }
}

object MyServer extends IOApp {

  import org.http4s.server.blaze._
  import Protocol._

  val service = HttpRoutes.of[IO] {
    case p @ POST -> Root / "test" =>
      for {
        env <- p.as(implicitly, jsonOf[IO, Envelope[Ping]])
        resp <- Ok(Envelope(Pong(env.value.seqNr)))(implicitly, jsonEncoderOf)
      } yield resp
  }

  override def run(args: List[String]): IO[ExitCode] = {
    BlazeServerBuilder[IO]
      .bindHttp(1234, "localhost")
      .withHttpApp(Router("/" -> service).orNotFound)
      .serve
      .compile
      .drain
      .as(ExitCode.Success)
  }
} 
Example 32
Source File: HttpService.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.app.service

import cats.effect.{ConcurrentEffect, Resource, Timer}
import io.circe.Json
import cats.implicits._
import fs2._
import javax.net.ssl.SSLContext
import jbok.network.http.server.middleware.{CORSMiddleware, GzipMiddleware, LoggerMiddleware, MetricsMiddleware}
import jbok.core.config.ServiceConfig
import jbok.core.api._
import jbok.crypto.ssl.SSLConfig
import jbok.network.rpc.RpcService
import jbok.network.rpc.http.Http4sRpcServer
import org.http4s.HttpRoutes
import org.http4s.implicits._
import org.http4s.server.{SSLClientAuthMode, Server}
import org.http4s.server.blaze.BlazeServerBuilder

final class HttpService[F[_]](
    config: ServiceConfig,
    sslConfig: SSLConfig,
    account: AccountAPI[F],
    admin: AdminAPI[F],
    block: BlockAPI[F],
    contract: ContractAPI[F],
    miner: MinerAPI[F],
    personal: PersonalAPI[F],
    transaction: TransactionAPI[F],
    sslOpt: Option[SSLContext]
)(implicit F: ConcurrentEffect[F], T: Timer[F]) {
  import jbok.codec.impl.circe._
  import _root_.io.circe.generic.auto._
  import jbok.codec.json.implicits._

  val rpcService: RpcService[F, Json] = {
    var service = RpcService[F, Json]
    if (config.apis.contains("account")) service = service.mount(account) else ()
    if (config.apis.contains("admin")) service = service.mount(admin) else ()
    if (config.apis.contains("block")) service = service.mount(block) else ()
    if (config.apis.contains("contract")) service = service.mount(contract) else ()
    if (config.apis.contains("miner")) service = service.mount(miner) else ()
    if (config.apis.contains("personal")) service = service.mount(personal) else ()
    if (config.apis.contains("transaction")) service = service.mount(transaction) else ()
    service
  }

  val routes: HttpRoutes[F] = Http4sRpcServer.routes(rpcService)

  private val builder: F[BlazeServerBuilder[F]] = {
    val httpApp = for {
      exportRoute <- MetricsMiddleware.exportService[F]
      withMetrics <- MetricsMiddleware[F](routes, config.enableMetrics)
      withLogger = LoggerMiddleware[F](config.logHeaders, config.logBody)((withMetrics <+> exportRoute).orNotFound)
      withCORS   = CORSMiddleware[F](withLogger, config.allowedOrigins)
      app        = GzipMiddleware[F](withCORS)
    } yield app

    val builder = httpApp.map { app =>
      BlazeServerBuilder[F]
        .withHttpApp(app)
        .withNio2(true)
        .enableHttp2(config.enableHttp2)
        .withWebSockets(config.enableWebsockets)
        .bindHttp(config.port, config.local)
    }

    val sslLClientAuthMode = sslConfig.clientAuth match {
      case "NotRequested" => SSLClientAuthMode.NotRequested
      case "Requested"    => SSLClientAuthMode.Requested
      case "Required"     => SSLClientAuthMode.Requested
      case x              => throw new IllegalArgumentException(s"SSLClientAuthMode ${x} is not supported")
    }

    sslOpt match {
      case Some(ssl) => builder.map(_.withSSLContext(ssl, sslLClientAuthMode))
      case None      => builder.map(_.enableHttp2(false))
    }
  }

  val resource: Resource[F, Server[F]] =
    Resource.liftF(builder).flatMap(_.resource)

  val stream: Stream[F, Unit] =
    if (config.enable) {
      Stream.eval(builder).flatMap(_.serve).drain
    } else {
      Stream.empty
    }
}