/tapir

tapir, or Typed API descRiptions

Primary LanguageScalaApache License 2.0Apache-2.0

tapir, or Typed API descRiptions

Join the chat at https://gitter.im/softwaremill/tapir Build Status Maven Central

With tapir you can describe HTTP API endpoints as immutable Scala values. Each endpoint can contain a number of input parameters, error-output parameters, and normal-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:
  • a client, which is a function from input parameters to output parameters. Currently supported: sttp.
  • documentation. Currently supported: OpenAPI.

Teaser

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

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

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

//

import tapir.docs.openapi._
import tapir.openapi.circe.yaml._

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

//

import tapir.server.akkahttp._
import akka.http.scaladsl.server.Route
import scala.concurrent.Future

def bookListingLogic(bfy: BooksFromYear, 
                     limit: Limit,  
                     at: AuthToken): Future[Either[String, List[Book]]] =
  Future.successful(Right(List(Book("The Sorrows of Young Werther"))))
val booksListingRoute: Route = booksListing.toRoute(bookListingLogic _)

//

import tapir.client.sttp._
import com.softwaremill.sttp._

val booksListingRequest: Request[Either[String, List[Book]], Nothing] = booksListing
  .toSttpRequest(uri"http://localhost:8080")
  .apply(BooksFromYear("SF", 2016), 20, "xyz-abc-123")

Documentation

tapir documentation is available at tapir-scala.readthedocs.io.

Quickstart with sbt

Add the following dependency:

"com.softwaremill.tapir" %% "tapir-core" % "0.7.6"

You'll need partial unification enabled in the compiler (alternatively, you'll need to manually provide type arguments in some cases):

scalacOptions += "-Ypartial-unification"

Then, import:

import tapir._

And finally, type endpoint. and see where auto-complete gets you!


Sidenote for scala 2.12.4 and higher: if you encounter an issue with compiling your project because of a StackOverflowException related to this scala bug, please increase your stack memory. Example:

sbt -J-Xss4M clean compile

Contributing

Tapir is an early stage project. Everything might change. All suggestions welcome :)

See the list of issues and pick one! Or report your own.

If you are having doubts on the why or how something works, don't hesitate to ask a question on gitter or via github. This probably means that the documentation, scaladocs or code is unclear and be improved for the benefit of all.