admin管理员组文章数量:1122846
Is there any way to extract the endpoint path template as input for Tapir endpoint (to be used inside of the serverLogic
)? Something like
in(extractFromRequest(_.uri))
but not from ServerRequest
but from Endpoint
So instead of /create-user/john
I would like to get /create-user/{username}
Is there any way to extract the endpoint path template as input for Tapir endpoint (to be used inside of the serverLogic
)? Something like
in(extractFromRequest(_.uri))
but not from ServerRequest
but from Endpoint
So instead of /create-user/john
I would like to get /create-user/{username}
1 Answer
Reset to default 3The method you are looking for is showPathTemplate
from Endpoint
object.
Just doing something like the following would be enough to get that value
endpoint
.in("some-path")
.in(path[String]("some-user"))
.showPathTemplate() // this returns /some-path/{some-user}
showPathTemplate
the method has some params if you need to customize the value returned
A full example to use the template path inside your business logic could be like the following
// just a case class to use it as an output response
case class PathAndUserResponse(path: String, user: String)
// the json serialization, in my case I use jsoniter for this example
implicit val jsonCodec: JsonValueCodec[PathAndUserResponse] =
JsonCodecMaker.make
// the endpoint definition without the businessLogic
val endpointSpec = endpoint
.in("some-path")
.in(path[String]("some-user"))
.out(jsonBody[PathAndUserResponse])
// the template path is just an string
val templatePath = endpointSpec.showPathTemplate()
// the endpoint with the logic implemented using the template path
val fullEndpoint = endpointSpec
.serverLogic[Future](user =>
Future(
Right(
PathAndUserResponse(
templatePath, // the template path extracted from the endpoint definition used inside the business logic
user // the user received in the path param
)
)
)
)
A unit test that validates you are getting the expected output following the docs from tapir - testing. In this case I'm using scala test
lazy val stubBackend =
TapirStubInterpreter(SttpBackendStub.asynchronousFuture)
.whenServerEndpoint(fullEndpoint)
.thenRunLogic()
.backend()
val userValue = "user-value"
basicRequest
.get(uri"https://test.com/some-path/$userValue")
.response(asJson[PathAndUserResponse])
.send(stubBackend)
.map(_.body.value should be(PathAndUserResponse(templatePath, userValue)))
From the scaladoc of showPathTemplate
/** Shows endpoint path, by default all parametrised path and query components are replaced by {param_name} or {paramN}, e.g. for
* {{{
* endpoint.in("p1" / path[String] / query[String]("par2"))
* }}}
* returns `/p1/{param1}?par2={par2}`
*
* @param includeAuth
* Should authentication inputs be included in the result.
* @param showNoPathAs
* How to show the path if the endpoint does not define any path inputs.
* @param showPathsAs
* How to show [[Tapir.paths]] inputs (if at all), which capture multiple paths segments
* @param showQueryParamsAs
* How to show [[Tapir.queryParams]] inputs (if at all), which capture multiple query parameters
*/
def showPathTemplate(
showPathParam: (Int, PathCapture[_]) => String = (index, pc) => pc.name.map(name => s"{$name}").getOrElse(s"{param$index}"),
showQueryParam: Option[(Int, Query[_]) => String] = Some((_, q) => s"${q.name}={${q.name}}"),
includeAuth: Boolean = true,
showNoPathAs: String = "*",
showPathsAs: Option[String] = Some("*"),
showQueryParamsAs: Option[String] = Some("*")
): String
you can also see the value showPathTemplateTestData from EnpointTest with different endpoint definitions and the expected output
val showPathTemplateTestData = List(
(endpoint, "*"),
(endpoint.in(""), "/"),
(endpoint.in("p1"), "/p1"),
(endpoint.in("p1" / "p2"), "/p1/p2"),
(endpoint.securityIn("p1").in("p2"), "/p1/p2"),
(endpoint.in("p1" / path[String]), "/p1/{param1}"),
(endpoint.in("p1" / path[String].name("par")), "/p1/{par}"),
(endpoint.in("p1" / query[String]("par")), "/p1?par={par}"),
(endpoint.in("p1" / query[String]("par1") / query[String]("par2")), "/p1?par1={par1}&par2={par2}"),
(endpoint.in("p1" / path[String].name("par1") / query[String]("par2")), "/p1/{par1}?par2={par2}"),
(endpoint.in("p1" / auth.apiKey(query[String]("par2"))), "/p1?par2={par2}"),
(endpoint.in("p2" / path[String]).mapIn(identity(_))(identity(_)), "/p2/{param1}"),
(endpoint.in("p1/p2"), "/p1%2Fp2"),
(endpoint.in(pathAllowedCharacters), "/" + pathAllowedCharacters),
(endpoint.in("p1" / paths), "/p1/*"),
(endpoint.in("p1").in(queryParams), "/p1?*"),
(
endpoint.in("p1" / "p2".schema(_.hidden(true)) / query[String]("par1") / query[String]("par2").schema(_.hidden(true))),
"/p1?par1={par1}"
),
(endpoint.in("not" / "allowed" / "chars" / "hi?hello"), "/not/allowed/chars/hi%3Fhello")
)
also it is the method used in the observability module to add the labels
import sttp.tapir.server.metrics.MetricLabels
val labels = MetricLabels(
forRequest = List(
"path" -> { case (ep, _) => ep.showPathTemplate() }, // here
"protocol" -> { case (_, req) => req.protocol }
),
forResponse = Nil
)
本文标签: scalaHow extract endpoint path template in TapirStack Overflow
版权声明:本文标题:scala - How extract endpoint path template in Tapir - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736308606a1933720.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论