Airframe HTTP: A lightweight web service builder


airframe-http is a library for creating HTTP web services.

  • airframe-http-finagle: Finagle as a backend HTTP server

Blog article: Airframe HTTP: Building Low-Friction Web Services Over Finagle



Maven Central

libraryDependencies += "org.wvlet.airframe" %% "airframe-http-finagle" %% AIRFRAME_VERSION

Defining HTTP Endpoints


import com.twitter.finagle.http.Request
import com.twitter.util.Future
import wvlet.airframe.http.{Endpoint, HttpMethod, HttpRequest}

object MyApi {
  case class User(name: String)
  case class NewUserRequest(name:String)
  case class ServerInfo(version:String, ua:String)

// [Optional] Specify a common prefix for all endpoints
trait MyApi {
  import MyApi._

  // Binding http path parameters (e.g., :name) to method arguments
  @Endpoint(method = HttpMethod.GET, path = "/user/:name")
  def getUser(name: String): User = User(name)

  // Receive a JSON request body {"user":"leo"} to generate NewUserRequest instance
  @Endpoint(method = HttpMethod.POST, path = "/user")
  def createNewUser(request:NewUserRequest): User = User(

  // To read http request headers, add a method argument of HttpRequest[Request] type
  @Endpoint(method = HttpMethod.GET, path = "/info")
  def getInfo(request: HttpRequest[Request]): ServerInfo = {
    ServerInfo("1.0", request.userAgent)

  // Returning Future[X] is also possible.
  // This style is convenient when you need to call another service that returns Future response.
  @Endpoint(method = HttpMethod.GET, path = "/info_f")
  def getInfoFuture(request: HttpRequest[Request]): Future[ServerInfo] = {
    Future.value(ServerInfo("1.0", request.userAgent))

This MyApi defines these http end points:

GET  /v1/user/:name    returns {"name":"..."}
POST /v1/user          returns {"name":"..."}
GET  /v1/info          returns {"version":"1.0", "ua":"...."}
GET  /v1/info_f        returns {"version":"1.0", "ua":"...."}

Mapping between JSON values and Scala objects will be handled automatically.

Starting A Finagle HTTP Server

To start a server, add airframe bindings based on finagleDefaultDesign:

import wvlet.airframe._
import wvlet.airframe.http.finagle._
import com.twitter.finagle.http.Request

// Define API routes. This will read all @Endpoint annotations in MyApi
// You can add more routes by using `.add[X]` method.
val router = Router.of[MyApi]

val design =
    // Register http routes
    // Configure port
    .bind[FinagleServerConfig].toInstance(FinagleServerConfig(port = 8080))[FinagleServer] { server =>
  // Finagle http server will start here

  // To keep runing the server, run `server.waitServerTermination`:
// The server will terminate here

Customizing Finagle

It’s possible to customize Finagle. For example, if you need to:

  • Customize Finagle filters, or
  • Start multiple Finagle HTTP servers with different configurations

see the examples here