|
9 | 9 | package no.ndla.network.tapir
|
10 | 10 |
|
11 | 11 | import cats.implicits.*
|
| 12 | +import io.circe.Json |
12 | 13 | import no.ndla.common.configuration.HasBaseProps
|
| 14 | +import no.ndla.common.model.api.UpdateOrDelete |
| 15 | +import sttp.apispec |
13 | 16 | import sttp.apispec.openapi.{Components, Contact, Info, License}
|
14 |
| -import sttp.apispec.{OAuthFlow, OAuthFlows, SecurityScheme} |
| 17 | +import sttp.apispec.{AnySchema, OAuthFlow, OAuthFlows, SchemaLike, SecurityScheme} |
15 | 18 | import sttp.tapir.*
|
16 |
| -import sttp.tapir.docs.openapi.OpenAPIDocsInterpreter |
| 19 | +import sttp.tapir.docs.openapi.{OpenAPIDocsInterpreter, OpenAPIDocsOptions} |
17 | 20 | import sttp.tapir.server.ServerEndpoint
|
18 | 21 |
|
19 | 22 | import scala.collection.immutable.ListMap
|
@@ -60,16 +63,49 @@ trait SwaggerControllerConfig {
|
60 | 63 | openIdConnectUrl = None
|
61 | 64 | )
|
62 | 65 |
|
63 |
| - private val docs = { |
64 |
| - val docs = OpenAPIDocsInterpreter().serverEndpointsToOpenAPI(swaggerEndpoints, info) |
| 66 | + /** NOTE: This is a hack to allow us to create nullable types in the specification. If possible this should probably |
| 67 | + * be replaced by a tapir alternative when that is possible. |
| 68 | + * |
| 69 | + * https://github.com/softwaremill/tapir/issues/2953 |
| 70 | + */ |
| 71 | + private val schemaPostProcessingFunctions: List[apispec.Schema => Option[apispec.Schema]] = List( |
| 72 | + UpdateOrDelete.replaceSchema |
| 73 | + ) |
| 74 | + |
| 75 | + private def postProcessSchema(schema: SchemaLike): SchemaLike = { |
| 76 | + schema match { |
| 77 | + case schema: AnySchema => schema |
| 78 | + case schema: apispec.Schema => |
| 79 | + val convertedSchema = schemaPostProcessingFunctions.foldLeft(None: Option[apispec.Schema]) { |
| 80 | + case (None, f) => f(schema) |
| 81 | + case (Some(convertedSchema), _) => Some(convertedSchema) |
| 82 | + } |
| 83 | + |
| 84 | + convertedSchema match { |
| 85 | + case Some(value) => value |
| 86 | + case None => |
| 87 | + val props = schema.properties.map { |
| 88 | + case (k, v: apispec.Schema) => k -> postProcessSchema(v) |
| 89 | + case (k, v) => k -> v |
| 90 | + } |
| 91 | + schema.copy(properties = props) |
| 92 | + } |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + private val docs: Json = { |
| 97 | + val options = OpenAPIDocsOptions.default |
| 98 | + val docs = OpenAPIDocsInterpreter(options).serverEndpointsToOpenAPI(swaggerEndpoints, info) |
65 | 99 | val generatedComponents = docs.components.getOrElse(Components.Empty)
|
66 |
| - val newComponents = generatedComponents.copy(securitySchemes = ListMap("oauth2" -> Right(securityScheme))) |
67 |
| - val docsWithComponents = docs.components(newComponents).asJson |
| 100 | + val newSchemas = generatedComponents.schemas.map { case (k, v) => k -> postProcessSchema(v) } |
| 101 | + val newComponents = generatedComponents.copy( |
| 102 | + securitySchemes = ListMap("oauth2" -> Right(securityScheme)), |
| 103 | + schemas = newSchemas |
| 104 | + ) |
| 105 | + val docsWithComponents = docs.components(newComponents).asJson |
68 | 106 | docsWithComponents.asJson
|
69 | 107 | }
|
70 | 108 |
|
71 |
| - def printSwagger(): Unit = println(docs.noSpaces) |
72 |
| - |
73 | 109 | def saveSwagger(): Unit = {
|
74 | 110 | import java.io.*
|
75 | 111 | val swaggerLocation = new File(s"./typescript/types-backend/openapi")
|
|
0 commit comments