Tapir
Rapid development of self-documenting APIs
Install / Use
/learn @softwaremill/TapirREADME

Welcome!
Intro
Tapir is a library to describe HTTP APIs, expose them as a server, consume as a client, and automatically document using open standards.
Tapir is fast and developer-friendly. The endpoint definition APIs are crafted with readability and discoverability in mind. Our Netty-based server is one of the best-performing Scala HTTP servers available.
endpoint
.get.in("hello").in(query[String]("name"))
.out(stringBody)
.handleSuccess(name => s"Hello, $name!")
Tapir integrates with all major Scala stacks, so you can use your favorite approach to Functional Programming, while leveraging all the benefits that Tapir brings!
Seamless integration with the Scala and HTTP ecosystems is one of Tapir's major strengths:
- all popular Scala HTTP server implementations are supported. You can define your entire API using Tapir, or expose Tapir-managed routes alongside "native" ones. This is especially useful when gradually adopting Tapir, or using it for selected use-cases.
- the Scala ecosystem is rich with libraries leveraging its type-safety and enhancing the developer's toolbox, that's why Tapir provides integrations with many of such custom type, JSON and observability libraries
- documentation can be generated in the OpenAPI, AsyncAPI and JSON Schema formats
Depending on how you'd prefer to explore Tapir, this documentation has three main sections:
- There's a number of tutorials, which provide a gentle introduction to the library
- Nothing compares to tinkering with working code, that's why we've prepared runnable examples, covering solutions to many "everyday" problems
- Finally, the reference documentation describes all of Tapir's aspects in depth - take a look at the menu on the left, starting with the "Endpoints" section
Documentation
Tapir documentation is available at tapir.softwaremill.com.
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
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.
||||
| :---: | :---: | :---: |
| <a href="https://www.adobe.com"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/adobe.png" alt="Adobe" width="160"/></a> | <a href="https://swisscom.com"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/swisscom.svg" alt="Swisscom" width="160"/></a> | <a href="https://swissborg.com"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/swissborg.png" alt="Swissborg" width="160"/></a> |
| <a href="https://kaizo.com"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/kaizo.png" alt="Kaizo" width="160"/></a> | <a href="https://www.process.st/"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/process_street.png" alt="Process Street" width="100"/></a> | <a href="https://www.tranzzo.com/"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/tranzzo.svg" alt="Tranzzo" width="160"/></a> |
| <a href="https://www.kelkoogroup.com"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/kelkoogroup.png" alt="Kelkoo group" width="160"/></a> | <a href="https://www.softwaremill.com/"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/softwaremill.png" alt="SoftwareMill" width="160"/></a> | <a href="https://www.carvana.com"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/carvana.svg" alt="Carvana" width="160"/></a> |
| <a href="https://www.moneyfarm.com"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/moneyfarm.png" alt="Moneyfarm" width="160"/></a> | <a href="https://www.ocadogroup.com/about-us/ocado-technology"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/ocado.png" alt="Ocado Technology" width="160"/></a> | <a href="https://www.wegtam.com"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/wegtam.svg" alt="Wegtam" width="160"/></a> |
| <a href="https://www.broad.app"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/broad.png" alt="Broad" width="160"/></a> | <a href="https://www.kensu.io?utm_source=github&utm_campaign=tapir"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/kensu.png" alt="Kensu" width="160"/></a> | <a href="https://www.colisweb.com"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/colisweb.png" alt="Colisweb" width="160"/></a> |
| <a href="http://www.iceo.co/"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/iceo.png" alt="iceo" width="160"/></a> | <a href="http://www.dpgrecruitment.nl/"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/dpg-recruitment.svg" alt="dpg" width="160"/></a> | <a href="https://www.hunters.security/"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/hunters.png" alt="hunters" width="160"/></a> |
| <a href="https://www.moia.io/en"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/moia.png" alt="moia" width="160"/></a> | <a href="https://www.pitsdatarecovery.net"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/pits.svg" alt="pits" width="100"/></a> | <a href="https://www.hootsuite.com"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/hootsuite.png" alt="hootsuite" width="160"/></a> |
| <a href="https://www.ematiq.com/"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/ematiq.png" alt="ematiq" width="100"/></a> | <a href="https://www.fugo.ai/"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/fugo.png" alt="fugo" width="100"/></a> | <a href="https://budgetbakers.com/"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/budgetbakers.svg" alt="budgetbakers" width="100"/></a> |
| <a href="https://flo.health"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/flo.svg" alt="flo" width="100"/></a> | | <a href="https://www.xing.com"><img src="https://github.com/softwaremill/tapir/raw/master/doc/adopters/xing.png" alt="xing" width="100"/></a> |
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.sttp4.SttpClientInterpreter
import sttp.client4.*
val booksListingRequest: Request[DecodeResult[Either[String, List[Book]]]] =
SttpClientInterpreter()
.toRequest(booksListing, Some(uri"http://localhost:8080"))
.apply((BooksQuery("SF", 2016), 20, "xyz-abc-123"))
Quickstart with sbt
Add the following dependency:
"com.softwaremill.sttp.tapir" %% "tapir-core" % "1.13.13"
Then, import:
import sttp.t
Related Skills
node-connect
337.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
prose
337.1kOpenProse VM skill pack. Activate on any `prose` command, .prose files, or OpenProse mentions; orchestrates multi-agent workflows.
frontend-design
83.1kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
Writing Hookify Rules
83.1kThis skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
