Pekko HTTP (Akka HTTP) style DSL directives for http4s with cats-effect IO. About 85% of all directives have been ported. Includes a test kit similar to Pekko's.
Cross-compiled for JVM, Scala.js, and Scala Native. Supports Scala 2.13 and Scala 3.
// build.sbt
libraryDependencies += "pl.iterators" %% "http4s-stir" % "0.4.1"
libraryDependencies += "pl.iterators" %% "http4s-stir-testkit" % "0.4.1" % TestA complete example you can run with scala-cli run .:
// Main.scala
//> using dep pl.iterators::http4s-stir::0.4.1
//> using dep org.http4s::http4s-ember-server::0.23.33
//> using dep org.http4s::http4s-circe::0.23.33
//> using dep io.circe::circe-generic::0.14.15
//> using dep org.typelevel::cats-effect::3.7.0
import org.http4s.Status
import org.http4s.ember.server.EmberServerBuilder
import org.http4s.circe.CirceEntityEncoder.*
import org.http4s.circe.CirceEntityDecoder.*
import io.circe.*
import io.circe.generic.semiauto.*
import cats.effect.{IO, IOApp}
import pl.iterators.stir.server.*
import pl.iterators.stir.server.Directives.*
var orders: List[Item] = Nil
final case class Item(name: String, id: Long)
final case class Order(items: List[Item])
given Codec[Item] = deriveCodec[Item]
given Codec[Order] = deriveCodec[Order]
def fetchItem(itemId: Long): IO[Option[Item]] = IO.delay {
orders.find(o => o.id == itemId)
}
def saveOrder(order: Order): IO[List[Item]] = {
orders = order.items ::: orders
IO.delay(orders)
}
val route: Route =
concat(
get {
pathPrefix("item" / LongNumber) { id =>
val maybeItem: IO[Option[Item]] = fetchItem(id)
onSuccess(maybeItem) {
case Some(item) => complete(item)
case None => complete(Status.NotFound)
}
}
},
post {
path("create-order") {
entity(as[Order]) { order =>
val saved: IO[List[Item]] = saveOrder(order)
onSuccess(saved) { _ =>
complete("order created")
}
}
}
}
)
object Main extends IOApp.Simple {
val run = EmberServerBuilder
.default[IO]
.withHttpApp(route.toHttpRoutes.orNotFound)
.build
.use(_ => IO.never)
}http4s-stir includes a test kit with familiar ~> routing test syntax:
// Main.test.scala
//> using test.dep pl.iterators::http4s-stir-testkit:0.4.1
//> using test.dep org.http4s::http4s-circe:0.23.33
//> using test.dep org.specs2::specs2-core:5.5.8
import org.http4s.Status
import org.http4s.circe.CirceEntityEncoder.*
import org.http4s.circe.CirceEntityDecoder.*
import cats.effect.IO
import cats.effect.unsafe.IORuntime
import org.specs2.mutable.Specification
import pl.iterators.stir.testkit.Specs2RouteTest
class MainRoutesSpec extends Specification with Specs2RouteTest {
override implicit val runtime: IORuntime = IORuntime.global
sequential
"The routes" should {
"create order" in {
Post("/create-order", Order(List(Item("foo", 42)))) ~> route ~> check {
responseAs[String] must contain("order created")
}
}
"retrieve an item if present" in {
orders = List(Item("foo", 42))
Get("/item/42") ~> route ~> check {
responseAs[Item] must beEqualTo(Item("foo", 42))
}
}
"return 404 if item is not present" in {
orders = List.empty
Get("/item/42") ~> route ~> check {
status must beEqualTo(Status.NotFound)
}
}
}
}Run with scala-cli test ..
For a more comprehensive example showcasing additional directives, see examples/Service.scala. Run it locally with sbt ~examples/reStart.
There's a compatibility layer, Http4sDirectives, that lets you embed existing http4s-dsl routes within stir routes.
Some Pekko HTTP directives are absent or modified:
CacheConditionDirectives,CodingDirectives,RangeDirectives- Directory listing in
FileAndResourceDirectives checkSameOrigininHeaderDirectives- Multipart form handling in
FormFieldDirectives AttributeDirectives,FramedEntityStreamingDirectives- Most of
WebSocketDirectives - Strict entity conversion,
withSizeLimit,withoutSizeLimit,requestEntityEmpty,requestEntityPresent,rejectEmptyResponse - Testkit differences: synchronous execution, no chunk support, limited request building, no WebSocket testing
stir something up (pv)
to cause an unpleasant emotion or problem to begin or grow
Some love http4s DSL but dislike Pekko's. Others feel the opposite. This library stirs things up by combining both.
Issues and PRs welcome at github.com/theiterators/http4s-stir.
Apache License 2.0. See LICENSE.
http4s-stir incorporates code adapted from Pekko HTTP, a fork of Akka HTTP.