From 95fd5da557bebbcbc2f01191797effbbec233195 Mon Sep 17 00:00:00 2001 From: Krzysztof Palcowski Date: Fri, 1 Mar 2024 17:20:33 +0100 Subject: [PATCH] Add error resposnes --- .../core/model/EnrichedRouteRepresentation.scala | 4 +++- .../baklava/core/model/RouteErrorResponse.scala | 9 +++++++++ .../baklava/core/model/RouteRepresentation.scala | 1 + .../formatter/openapi/OpenApiFormatterWorker.scala | 14 ++++++++++++-- .../baklava/formatter/SimpleDocsFormatter.scala | 4 ++++ 5 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 core/src/main/scala/pl/iterators/baklava/core/model/RouteErrorResponse.scala diff --git a/core/src/main/scala/pl/iterators/baklava/core/model/EnrichedRouteRepresentation.scala b/core/src/main/scala/pl/iterators/baklava/core/model/EnrichedRouteRepresentation.scala index e192551..e507320 100644 --- a/core/src/main/scala/pl/iterators/baklava/core/model/EnrichedRouteRepresentation.scala +++ b/core/src/main/scala/pl/iterators/baklava/core/model/EnrichedRouteRepresentation.scala @@ -1,5 +1,7 @@ package pl.iterators.baklava.core.model +import scala.util.Try + class EnrichedRouteRepresentation[Request, Response] private ( val routeRepresentation: RouteRepresentation[Request, Response], val enrichDescriptions: Seq[EnrichedDescription]) { @@ -50,6 +52,6 @@ object EnrichedDescription { description.toLowerCase .replace("inaccessible", "unauthorized") .split(" ") - .flatMap(s => statusCodesMap.get(s)) + .flatMap(s => Try(s.toInt).toOption.orElse(statusCodesMap.get(s))) .headOption } diff --git a/core/src/main/scala/pl/iterators/baklava/core/model/RouteErrorResponse.scala b/core/src/main/scala/pl/iterators/baklava/core/model/RouteErrorResponse.scala new file mode 100644 index 0000000..0d3ee7d --- /dev/null +++ b/core/src/main/scala/pl/iterators/baklava/core/model/RouteErrorResponse.scala @@ -0,0 +1,9 @@ +package pl.iterators.baklava.core.model + +final case class RouteErrorResponse[T](`result`: T, status: Int)(marshaller: T => String) { + lazy val jsonData: RouteErrorResponseJsonData = + RouteErrorResponseJsonData(marshaller(result), status) + + def resultName: String = result.getClass.getSimpleName.replaceAll("\\$", "") +} +final case class RouteErrorResponseJsonData(`type`: String, status: Int) diff --git a/core/src/main/scala/pl/iterators/baklava/core/model/RouteRepresentation.scala b/core/src/main/scala/pl/iterators/baklava/core/model/RouteRepresentation.scala index 990052c..3072b76 100644 --- a/core/src/main/scala/pl/iterators/baklava/core/model/RouteRepresentation.scala +++ b/core/src/main/scala/pl/iterators/baklava/core/model/RouteRepresentation.scala @@ -12,6 +12,7 @@ case class RouteRepresentation[Request, Response]( path: String, parameters: List[RouteParameterRepresentation[_]] = Nil, headers: List[RouteHeaderRepresentation] = Nil, + errorResponses: List[RouteErrorResponse[_]] = Nil, requestPredefinedValue: Option[Request] = None, responsePredefinedValue: Option[Response] = None, authentication: List[RouteSecurityGroup] = List.empty, diff --git a/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/OpenApiFormatterWorker.scala b/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/OpenApiFormatterWorker.scala index d3b689c..a98e0dd 100644 --- a/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/OpenApiFormatterWorker.scala +++ b/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/OpenApiFormatterWorker.scala @@ -10,6 +10,7 @@ import io.swagger.v3.oas.models.security.{SecurityRequirement, SecurityScheme} import pl.iterators.baklava.core.model._ import pl.iterators.baklava.formatter.openapi.builders.{OpenApiBuilder, OperationBuilder, PathItemBuilder} import pl.iterators.kebs.jsonschema.JsonSchemaWrapper + import scala.jdk.CollectionConverters._ class OpenApiFormatterWorker(jsonSchemaToSwaggerSchemaWorker: JsonSchemaToSwaggerSchemaWorker) { @@ -130,14 +131,23 @@ class OpenApiFormatterWorker(jsonSchemaToSwaggerSchemaWorker: JsonSchemaToSwagge .foreach { case (codeOpt, desc) => val code = codeOpt.get // get is safe here val apiResponse = new ApiResponse() - apiResponse.setDescription(desc.map(_.description).mkString("\n")) + if (code.intValue >= 200 && code.intValue < 204) { val mt = routeDtoHandlerToMediaType(route.routeRepresentation.response) apiResponse.setContent(new Content().addMediaType("application/json", mt)) + } else { + val mt = new MediaType + route.routeRepresentation.errorResponses.filter(er => er.status == code.intValue()).foreach { errorResponse => + val example = new Example() + example.setValue(s"""{"type": "${errorResponse.jsonData.`type`}", "status": ${errorResponse.status}}""") + mt.addExamples(errorResponse.resultName, example) + } + if (Option(mt.getExamples).nonEmpty) { + apiResponse.setContent(new Content().addMediaType("application/json", mt)) + } } - apiResponses.addApiResponse(code.intValue.toString, apiResponse) } apiResponses diff --git a/formatter/src/main/scala/pl/iterators/baklava/formatter/SimpleDocsFormatter.scala b/formatter/src/main/scala/pl/iterators/baklava/formatter/SimpleDocsFormatter.scala index bc3d3f8..3695ebe 100644 --- a/formatter/src/main/scala/pl/iterators/baklava/formatter/SimpleDocsFormatter.scala +++ b/formatter/src/main/scala/pl/iterators/baklava/formatter/SimpleDocsFormatter.scala @@ -127,6 +127,10 @@ class SimpleDocsFormatter extends Formatter { } .mkString("
")}"), Some(s"STATUS CODES${statusCodes.mkString("
")}"), + Option.when(r.errorResponses.nonEmpty) { + s"ERROR RESPONSES" + + s"${r.errorResponses.map(er => s"type: ${er.jsonData.`type`}, code: ${er.status}").mkString("
")}" + }, Option.when(r.parameters.nonEmpty) { s"PARAMETERS" + s"${r.parameters.map(h => s"${h.name} [${h.scalaType}] ${Option.when(h.required)(s"*").getOrElse("")}").mkString("
")}" +