如何将含查询参数的URL字符串转换为Tapir的EndpointInput?
解决Tapir中转换带查询参数的URL字符串为EndpointInput的问题
直接使用.in(string)确实无法解析URL中的路径和查询参数结构,因为Tapir会把整个字符串当作单一的输入字段,而非HTTP请求的结构化路径/参数。正确的做法是先解析URL,拆分出路径和查询参数,再用Tapir的结构化API构建对应的EndpointInput。
具体步骤与代码示例(Scala)
解析URL,拆分路径与查询参数
先用标准库解析目标URL,提取路径段和查询参数键值对:import java.net.URL import scala.jdk.CollectionConverters._ // 示例下一页URL val nextPageUrl = new URL("https://api.example.com/v1/data?page=3&per_page=20") // 提取路径(去除开头的/,拆分成路径段) val pathSegments = nextPageUrl.getPath.split("/").filter(_.nonEmpty) // 提取查询参数(转为Map) val queryParamsMap = Option(nextPageUrl.getQuery) .map(_.split("&").map(_.split("=", 2)) .filter(_.length == 2) .map { case Array(k, v) => k -> v } .toMap) .getOrElse(Map.empty)构建结构化的EndpointInput
用Tapir的pathSegments定义路径部分,结合queryParamsMap或单个query方法定义查询参数:import sttp.tapir._ import sttp.tapir.json.circe._ // 基础Endpoint定义 val baseEndpoint = endpoint.get.out(jsonBody[YourResponseModel]) // 拼接解析后的路径和查询参数到Endpoint val nextPageEndpoint = baseEndpoint .in(pathSegments(pathSegments: _*)) // 传入解析后的路径段 .in(queryParamsMap[String]) // 接收所有查询参数,若参数固定可改用单个query("page").int等动态复用解析逻辑(可选)
如果需要多次处理这类URL,可以封装一个工具方法:def urlToEndpointInput(url: URL): EndpointInput[Unit] = { val pathInput = pathSegments(url.getPath.split("/").filter(_.nonEmpty): _*) val queryInput = Option(url.getQuery) match { case Some(_) => queryParamsMap[String] case None => emptyInput } pathInput.and(queryInput) } // 使用示例 val dynamicEndpoint = baseEndpoint.in(urlToEndpointInput(nextPageUrl))
关键说明
- 避免直接用
.in(string):该方式会将整个URL字符串作为路径的一部分发送,导致请求地址错误(比如会发送https://your-base-url/https://api.example.com/data?page=2这类无效地址)。 - 结构化定义的优势:Tapir会自动处理路径编码、查询参数编码,同时保证请求结构符合HTTP规范,也便于后续的文档生成、输入验证等功能。
内容的提问来源于stack exchange,提问作者Awethon
相关产品推荐
相关产品推荐

