
sttp.apispec.openapi.internal.InternalSttpOpenAPICirceDecoders.scala Maven / Gradle / Ivy
package sttp.apispec
package openapi
package internal
import cats.syntax.all._
import io.circe._
import io.circe.syntax._
import io.circe.generic.semiauto.deriveDecoder
import sttp.apispec.internal.JsonSchemaCirceDecoders
import scala.collection.immutable.ListMap
trait InternalSttpOpenAPICirceDecoders extends JsonSchemaCirceDecoders {
implicit val referenceDecoder: Decoder[Reference] = deriveDecoder[Reference]
implicit def decodeReferenceOr[A: Decoder]: Decoder[ReferenceOr[A]] = referenceDecoder.either(Decoder[A])
def listMapStringADecoder[A: Decoder]: Decoder[ListMap[String, A]] =
Decoder.decodeOption(Decoder.decodeMapLike[String, A, ListMap]).map(_.getOrElse(ListMap.empty))
def listADecoder[A: Decoder]: Decoder[List[A]] =
Decoder.decodeOption(Decoder.decodeList[A]).map(_.getOrElse(Nil))
implicit def listMapStringReferenceOrADecoder[A: Decoder]: Decoder[ListMap[String, ReferenceOr[A]]] =
listMapStringADecoder
implicit def listMapStringMediaTypeDecoder: Decoder[ListMap[String, MediaType]] =
listMapStringADecoder
implicit def listMapStringEncodingDecoder: Decoder[ListMap[String, Encoding]] =
listMapStringADecoder
implicit def listMapStringStringDecoder: Decoder[ListMap[String, String]] =
listMapStringADecoder
implicit val tagDecoder: Decoder[Tag] = withExtensions(deriveDecoder[Tag])
// #79: all OAuth flow object MUST include a scopes field, but it MAY be empty.
implicit val oauthFlowDecoder: Decoder[OAuthFlow] = withExtensions(deriveDecoder[OAuthFlow])
implicit val oauthFlowsDecoder: Decoder[OAuthFlows] = withExtensions(deriveDecoder[OAuthFlows])
implicit val securitySchemeDecoder: Decoder[SecurityScheme] = withExtensions(deriveDecoder[SecurityScheme])
implicit val contactDecoder: Decoder[Contact] = withExtensions(deriveDecoder[Contact])
implicit val licenseDecoder: Decoder[License] = withExtensions(deriveDecoder[License])
implicit val infoDecoder: Decoder[Info] = withExtensions(deriveDecoder[Info])
implicit val serverVariableDecoder: Decoder[ServerVariable] = deriveDecoder[ServerVariable]
implicit val serverDecoder: Decoder[Server] = withExtensions(deriveDecoder[Server])
implicit val linkDecoder: Decoder[Link] = deriveDecoder[Link]
implicit val parameterInDecoder: Decoder[ParameterIn] = Decoder.decodeString.emap {
case ParameterIn.Path.value => ParameterIn.Path.asRight
case ParameterIn.Query.value => ParameterIn.Query.asRight
case ParameterIn.Cookie.value => ParameterIn.Cookie.asRight
case ParameterIn.Header.value => ParameterIn.Header.asRight
case err => s"$err is not a valid ParameterIn value".asLeft
}
implicit val parameterStyleDecoder: Decoder[ParameterStyle] = Decoder.decodeString.emap {
case ParameterStyle.Form.value => ParameterStyle.Form.asRight
case ParameterStyle.Label.value => ParameterStyle.Label.asRight
case ParameterStyle.Matrix.value => ParameterStyle.Matrix.asRight
case ParameterStyle.Simple.value => ParameterStyle.Simple.asRight
case ParameterStyle.SpaceDelimited.value => ParameterStyle.SpaceDelimited.asRight
case ParameterStyle.DeepObject.value => ParameterStyle.DeepObject.asRight
case ParameterStyle.PipeDelimited.value => ParameterStyle.PipeDelimited.asRight
case err => s"$err is not a valid ParameterStyle value".asLeft
}
implicit val exampleDecoder: Decoder[Example] = withExtensions(deriveDecoder[Example])
implicit val encodingDecoder: Decoder[Encoding] = withExtensions(deriveDecoder[Encoding])
implicit val headerDecoder: Decoder[Header] = deriveDecoder[Header]
implicit val mediaTypeDecoder: Decoder[MediaType] = withExtensions(deriveDecoder[MediaType])
implicit val requestBodyDecoder: Decoder[RequestBody] = withExtensions(deriveDecoder[RequestBody])
implicit val responseDecoder: Decoder[Response] = withExtensions(deriveDecoder[Response])
implicit val responsesKeyDecoder: KeyDecoder[ResponsesKey] = {
val ResponseRange = "(1|2|3|4|5)XX".r
val ResponseCode = "([1|2|3|4|5]\\d\\d)".r
KeyDecoder.decodeKeyString.map {
case "default" => ResponsesDefaultKey
case ResponseRange(range) => ResponsesRangeKey(range.toInt)
case ResponseCode(code) => ResponsesCodeKey(code.toInt)
case key => sys.error(s"'$key' Not a valid responsekey")
}
}
implicit val responsesDecoder: Decoder[Responses] = withExtensions(Decoder.instance { c =>
for {
responses <- c
.as[JsonObject]
.flatMap(json => json.remove("extensions").asJson.as[ListMap[ResponsesKey, ReferenceOr[Response]]])
extensions <- c.getOrElse[ListMap[String, ExtensionValue]]("extensions")(ListMap.empty)
} yield Responses(responses, extensions)
})
implicit val parameterDecoder: Decoder[Parameter] = withExtensions(deriveDecoder[Parameter])
implicit val callbackDecoder: Decoder[Callback] = Decoder.instance { c =>
for {
pathItems <- c.as[JsonObject].flatMap(json => json.asJson.as[ListMap[String, ReferenceOr[PathItem]]])
} yield Callback(pathItems)
}
implicit val operationDecoder: Decoder[Operation] = {
implicit def listReference[A: Decoder]: Decoder[List[A]] =
listADecoder
withExtensions(deriveDecoder[Operation])
}
implicit val pathItemDecoder: Decoder[PathItem] = {
implicit def listReference[A: Decoder]: Decoder[List[A]] =
listADecoder
withExtensions(deriveDecoder[PathItem])
}
implicit val pathsDecoder: Decoder[Paths] = withExtensions(Decoder.instance { c =>
for {
pathItems <- c.as[JsonObject].flatMap(json => json.remove("extensions").asJson.as[ListMap[String, PathItem]])
extensions <- c.getOrElse[ListMap[String, ExtensionValue]]("extensions")(ListMap.empty)
} yield Paths(pathItems, extensions)
})
implicit val componentsDecoder: Decoder[Components] = withExtensions(Decoder.instance { c =>
type Comp[A] = ListMap[String, ReferenceOr[A]]
def getComp[A: Decoder](name: String): Decoder.Result[Comp[A]] =
c.get[Option[Comp[A]]](name).map(_.getOrElse(ListMap.empty))
for {
schemas <- c.get[Option[ListMap[String, SchemaLike]]]("schemas").map(_.getOrElse(ListMap.empty))
responses <- getComp[Response]("responses")
parameters <- getComp[Parameter]("parameters")
examples <- getComp[Example]("examples")
requestBodies <- getComp[RequestBody]("requestBodies")
headers <- getComp[Header]("headers")
securitySchemes <- getComp[SecurityScheme]("securitySchemes")
links <- getComp[Link]("links")
callbacks <- getComp[Callback]("callbacks")
extensions <- c.getOrElse[ListMap[String, ExtensionValue]]("extensions")(ListMap.empty)
} yield Components(
schemas,
responses,
parameters,
examples,
requestBodies,
headers,
securitySchemes,
links,
callbacks,
extensions
)
})
implicit val openAPIDecoder: Decoder[OpenAPI] = withExtensions(Decoder.instance { c =>
for {
openapi <- c.get[String]("openapi")
info <- c.get[Info]("info")
jsonSchemaDialect <- c.get[Option[String]]("jsonSchemaDialect")
tags <- c.getOrElse[List[Tag]]("tags")(Nil)
servers <- c.getOrElse[List[Server]]("servers")(Nil)
paths <- c.getOrElse[Paths]("paths")(Paths.Empty)
webhooks <- c.get[Option[Map[String, ReferenceOr[PathItem]]]]("webhooks")
components <- c.get[Option[Components]]("components")
security <- c.getOrElse[List[SecurityRequirement]]("security")(Nil)
extensions <- c.getOrElse[ListMap[String, ExtensionValue]]("extensions")(ListMap.empty)
} yield OpenAPI(openapi, info, jsonSchemaDialect, tags, servers, paths, webhooks, components, security, extensions)
})
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy