tapir

Declarative, type-safe web endpoints library.

tapir

Intro

With tapir, you can describe HTTP API endpoints as immutable Scala values. Each endpoint can contain a number of input and output parameters. An endpoint specification can be interpreted as:

  • a server, given the “business logic”: a function, which computes output parameters based on input parameters. Currently supported:

    • Akka HTTP Routes/Directives

    • Http4s HttpRoutes[F] (using cats-effect or ZIO)

    • Netty (using Futures, cats-effect or ZIO)

    • Helidon Níma (using JVM 21 Virtual Threads and direct style)

    • Finatra http.Controller

    • Pekko HTTP Routes/Directives

    • Play Route

    • Vert.X Router => Route (using Futures, cats-effect or ZIO)

    • ZIO Http Http

    • Armeria HttpServiceWithRoutes (using Futures, cats-effect or ZIO)

    • JDK HTTP HttpHandler (simple, synchronous API only)

    • aws through Lambda/SAM/Terraform

    • gRPC

  • a client, which is a function from input parameters to output parameters. Currently supported:

  • documentation. Currently supported:

Depending on how you prefer to explore the library, take a look at one of the examples or read on for a more detailed description of how tapir works! ScalaDocs are available at javadoc.io.

Why tapir?

  • type-safety: compile-time guarantees, develop-time completions, read-time information

  • declarative: separate the shape of the endpoint (the “what”), from the server logic (the “how”)

  • OpenAPI / Swagger integration: generate documentation from endpoint descriptions

  • observability: leverage the metadata to report rich metrics and tracing information

  • abstraction: re-use common endpoint definitions, as well as individual inputs/outputs

  • library, not a framework: integrates with your stack

Adopt a tapir

Availability

Tapir is available:

  • all modules - Scala 2.12 and 2.13 on the JVM (Java 11+)

  • selected modules - Scala 3 on the JVM (Java 11+)

  • selected modules - Scala 2.12, 2.13 and 3 using Scala.JS

  • selected modules - Scala 2.12, 2.13 and 3 using Scala Native

Tapir is licensed under Apache2, the source code is available on GitHub.

Adopters

Is your company already using tapir? We’re continually expanding the “adopters” section in the documentation; the more the merrier! It would be great to feature your company’s logo, but in order to do that, we’ll need written permission to avoid any legal misunderstandings.

Please email us at tapir@softwaremill.com from your company’s email with a link to your logo (if we can use it, of course!) or with details who to kindly ask for permission to feature the logo in tapir’s documentation. We’ll handle the rest.

Thank you!

Adobe Swisscom Swissborg
Kaizo Process Street Tranzzo
Kelkoo group SoftwareMill Carvana
Moneyfarm Ocado Wegtam
Broad Kensu Colisweb
iceo dpg hunters
moia pits hootsuite

Code teaser

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

type Limit = Int
type AuthToken = String
case class BooksQuery(genre: String, year: Int)
case class Book(title: String)


// Define an endpoint

val booksListing: PublicEndpoint[(BooksQuery, Limit, AuthToken), String, List[Book], Any] =
  endpoint
    .get
    .in(("books" / path[String]("genre") / path[Int]("year")).mapTo[BooksQuery])
    .in(query[Limit]("limit").description("Maximum number of books to retrieve"))
    .in(header[AuthToken]("X-Auth-Token"))
    .errorOut(stringBody)
    .out(jsonBody[List[Book]])


// Generate OpenAPI documentation

import sttp.apispec.openapi.circe.yaml._
import sttp.tapir.docs.openapi.OpenAPIDocsInterpreter

val docs = OpenAPIDocsInterpreter().toOpenAPI(booksListing, "My Bookshop", "1.0")
println(docs.toYaml)


// Convert to akka-http Route

import sttp.tapir.server.akkahttp.AkkaHttpServerInterpreter
import akka.http.scaladsl.server.Route
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def bookListingLogic(bfy: BooksQuery,
                     limit: Limit,
                     at: AuthToken): Future[Either[String, List[Book]]] =
  Future.successful(Right(List(Book("The Sorrows of Young Werther"))))

val booksListingRoute: Route = AkkaHttpServerInterpreter()
  .toRoute(booksListing.serverLogic((bookListingLogic _).tupled))


// Convert to sttp Request

import sttp.tapir.client.sttp.SttpClientInterpreter
import sttp.client3._

val booksListingRequest: Request[DecodeResult[Either[String, List[Book]]], Any] =
  SttpClientInterpreter()
    .toRequest(booksListing, Some(uri"http://localhost:8080"))
    .apply((BooksQuery("SF", 2016), 20, "xyz-abc-123"))

Other sttp projects

sttp is a family of Scala HTTP-related projects, and currently includes:

  • sttp client: the Scala HTTP client you always wanted!

  • sttp tapir: this project

  • sttp model: simple HTTP model classes (used by client & tapir)

  • sttp shared: shared web socket, FP abstractions, capabilities and streaming code.

  • sttp apispec: OpenAPI, AsyncAPI and JSON Schema models.

Sponsors

Development and maintenance of sttp tapir is sponsored by SoftwareMill, a software development and consulting company. We help clients scale their business through software. Our areas of expertise include backends, distributed systems, blockchain, machine learning and data analytics.

Commercial Support

We offer commercial support for sttp and related technologies, as well as development services. Contact us to learn more about our offer!

Table of contents

Endpoints

Server interpreters