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.
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")
tapir documentation is available at tapir-scala.readthedocs.io.
Add the following dependency:
"com.softwaremill.tapir" %% "tapir-core" % "0.11.4"
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
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.