Running as a Play server

To expose endpoint as a play-server first add the following dependencies:

"com.softwaremill.sttp.tapir" %% "tapir-play-server" % "1.0.0-M8"

and (if you don’t already depend on Play)

"com.typesafe.play" %% "play-akka-http-server" % "2.8.15"

or

"com.typesafe.play" %% "play-netty-server" % "2.8.15"

depending on whether you want to use netty or akka based http-server under the hood.

Then import the object:

import sttp.tapir.server.play.PlayServerInterpreter

The toRoutes method requires a single, or a list of ServerEndpoints, which can be created by adding server logic to an endpoint. For example:

import sttp.tapir._
import sttp.tapir.server.play.PlayServerInterpreter
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import akka.stream.Materializer
import play.api.routing.Router.Routes

implicit val materializer: Materializer = ???

def countCharacters(s: String): Future[Either[Unit, Int]] = 
  Future(Right[Unit, Int](s.length))

val countCharactersEndpoint: PublicEndpoint[String, Unit, Int, Any] = 
  endpoint.in(stringBody).out(plainBody[Int])
val countCharactersRoutes: Routes = 
  PlayServerInterpreter().toRoutes(countCharactersEndpoint.serverLogic(countCharacters _))

Bind the routes

Creating the HTTP server manually

An HTTP server can then be started as in the following example:

import play.core.server._
import play.api.routing.Router.Routes

val aRoute: Routes = ???

object Main {
  // JVM entry point that starts the HTTP server
  def main(args: Array[String]): Unit = {
    val playConfig = ServerConfig(port =
      sys.props.get("http.port").map(_.toInt).orElse(Some(9000))
    )
    NettyServer.fromRouterWithComponents(playConfig) { components =>
      aRoute
    }
  }
}

As part of an existing Play application

Or, if you already have an existing Play application, you can create a Router class and bind it to the application.

First, add a line like following in the routes files:

->      /api                        api.ApiRouter

Then create a class like this:

class ApiRouter @Inject() () extends SimpleRouter {
  override def routes: Routes = {
    anotherRoutes.orElse(tapirGeneratedRoutes)
  }
}

Find more details about how to bind a Router to your application in the Play framework documentation.

Web sockets

The interpreter supports web sockets, with pipes of type Flow[REQ, RESP, Any]. See web sockets for more details.

The interpreter does not expose control frames (Ping, Pong and Close), so any setting regarding them are discarded, however those that are emitted are sent to the client.

Configuration

The interpreter can be configured by providing a PlayServerOptions value, see server options for details.