I have created tapir endpoint:
val getEndpoint = endpoint.get
.securityIn(auth.bearer[String]())
.in("players" / path[PlayerId]("playerId"))
.in(query[PlayerRequest]("query"))
.errorOut(someErrors)
Now, I would like to read all passed values: bearer token
, playerId
and query
. So I created ZIO
server logic:
PlayersEndpoint.getEndpoint.zServerLogic { case (playerId, query) =>
//some logic to do...
}
It works fine, but whithout bearer token
. Here I could not read bearer token
. I tried to change it to something like:
PlayersEndpoint.getEndpoint.zServerSecurityLogic{ case (token) =>
//do smth with token
}.zServerLogic { case (playerId, query) =>
//some logic to do...
}
But it did not work. I would like to read all 3 values and decide about what to do after checking token. Docs and examples are very poor and do not show how to read tokens from tapir. Do you know how I should do it correctly?
You can try this:
import org.http4s.blaze.server.BlazeServerBuilder
import org.http4s.server.Router
import sttp.tapir.server.http4s.ztapir.ZHttp4sServerInterpreter
import sttp.tapir.ztapir._
import zio._
import zio.interop.catz._
import cats.implicits._
object TapirExample extends ZIOAppDefault {
type Env = Any
// fake type
type PlayerId = Int
type PlayerRequest = Long
def authLogic(token: String): ZIO[Any, String, String] = {
if (token != "secret") ZIO.fail("user not login")
else ZIO.succeed(token)
}
val authEndpoint: ZPartialServerEndpoint[Any, String, String, Unit, String, Unit, Any] =
endpoint
.securityIn(auth.bearer[String]())
.errorOut(stringBody)
.zServerSecurityLogic(authLogic)
val getEndpoint =
authEndpoint
.get
.in("players" / path[PlayerId]("playerId"))
.in(query[PlayerRequest]("query"))
.out(stringBody)
.serverLogic(token => queryTuple => getLogic(token, queryTuple._1, queryTuple._2))
val getRoute =
ZHttp4sServerInterpreter()
.from(
List(
getEndpoint.widen[Env]
)
).toRoutes
def getLogic(token: String, playerId: PlayerId, request: PlayerRequest): ZIO[Any, Nothing, String] = {
ZIO.succeed(
s"""
| token: $token
| id: $playerId
| request: $request
|""".stripMargin)
}
override def run: ZIO[Any with ZIOAppArgs with Scope, Any, Any] = {
val io = ZIO.runtime[Env].flatMap { _ =>
for {
_ <- ZIO.executor.flatMap(executor =>
BlazeServerBuilder[ZIO[Env, Throwable, *]]
.withExecutionContext(executor.asExecutionContext)
.bindHttp(9090, "0.0.0.0")
.withHttpApp(
Router(
"/" -> (
getRoute
)
).orNotFound
)
.serve
.compile
.drain)
} yield ()
}
io
}
}
And the library version is
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / scalaVersion := "2.13.8"
lazy val root = (project in file("."))
.settings(
name := "playground"
)
val tapirVersion = "1.2.4"
val allDependency = Seq(
"com.softwaremill.sttp.tapir" %% "tapir-http4s-server-zio" % tapirVersion,
"org.http4s" %% "http4s-blaze-server" % "0.23.13",
)
libraryDependencies ++= allDependency
addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.13.2" cross CrossVersion.full)
Test by curl
$ curl --location --request GET 'localhost:9090/players/233?query=334' \
--header 'Authorization: Bearer wrongtoken'
user not login
$ curl --location --request GET 'localhost:9090/players/233?query=334' \
--header 'Authorization: Bearer secret'
token: secret
id: 233
request: 334
refer:
I don't have IDE to give you the exact code but the idea is that the return of your zServerSecurityLogic
can be used in the following zServerLogic
.
Usually you'd validate the token in the zServerSecurityLogic
and return some kind of User
value that you can use as input in zServerLogic
.
But you can also "do nothing" in the security logic and just passthrough the token so that it's available in the main logic.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.