如何在sttp.tapir中忽略JSON请求缺失字段与响应空字段?
解决Tapir请求忽略缺失字段且响应不返回空字段的问题
要实现这两个需求,核心是通过配置Circe的编解码器(Tapir的JSON处理依赖Circe)调整解析和序列化行为,以下是具体实现步骤:
1. 请求解析忽略缺失字段
默认情况下,Circe的严格解码器会在请求体缺失字段时抛出错误,可通过两种方式处理:
方式A:将请求字段设为可选类型(Option)
把Request类的字段改为Option[String],缺失字段时会自动解析为None,不会触发错误:
case class Request(field1: Option[String], field2: Option[String])
方式B:给字段设置默认值并启用Circe默认值支持
如果希望缺失字段时使用默认值(比如空字符串),先给case class字段添加默认值,再配置Circe解码器启用默认值解析:
// 带默认值的请求类 case class Request(field1: String = "", field2: String = "") // 导入Circe Generic Extras相关工具 import io.circe.generic.extras.Configuration import io.circe.generic.extras.semiauto._ // 配置Circe支持默认值解析,同时可忽略请求中多余的字段 implicit val circeConfig: Configuration = Configuration.default .withDefaults // 缺失字段时使用case class的默认值 .withIgnoreExtras // 忽略请求中未定义的多余字段(可选) // 为Request派生自定义解码器 implicit val requestDecoder: io.circe.Decoder[Request] = deriveDecoder[Request]
2. 响应中空字段不返回
要让响应自动移除空值(或空字符串)字段,需配置Circe编码器过滤这些字段:
情况1:响应字段为Option类型
如果Response字段是Option[String],直接配置编码器移除null值即可:
case class Response(field1: Option[String], field2: Option[String]) // 派生编码器并移除null值字段 implicit val responseEncoder: io.circe.Encoder[Response] = deriveEncoder[Response].mapJson(_.dropNullValues)
情况2:响应字段为非可选类型(如String)
如果字段是普通String,要移除空字符串字段,需要额外过滤字符串空值:
case class Response(field1: String, field2: String) implicit val responseEncoder: io.circe.Encoder[Response] = deriveEncoder[Response].mapJson { json => json.mapObject(obj => obj.filter { case (_, value) => !value.isString || value.asString.exists(_.nonEmpty) }) }
3. 关联Tapir端点配置
确保Tapir的jsonBody使用自定义编解码器,若用了方式B,需移除import sttp.tapir.generic.auto._避免默认编解码器冲突:
// 使用自定义编解码器的请求体 private lazy val reqBody = jsonBody[Request] // 使用自定义编解码器的响应体 private lazy val respBody = jsonBody[Response] // 端点定义保持不变 private val postEP: Endpoint[Unit, (CommonHeader, Request), (StatusCode, ErrorInfo), (StatusCode, Response), Any] = baseEndpoint.post .in("test") .in(reqBody) .out(statusCode.and(respBody))
内容的提问来源于stack exchange,提问作者Sourav Tathgur
相关产品推荐
相关产品推荐

