Skip to content

Commit

Permalink
Fix multiple issues with docs in generating OpenAPI (zio#3132) (zio#3147
Browse files Browse the repository at this point in the history
)
  • Loading branch information
987Nabil authored Sep 29, 2024
1 parent 017d975 commit 13ecf37
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,11 @@ object OpenAPIGenSpec extends ZIOSpecDefault {
assertTrue(json == toJsonAst(expectedJson))
},
test("simple endpoint to OpenAPI") {
val generated = OpenAPIGen.fromEndpoints("Simple Endpoint", "1.0", simpleEndpoint.tag("simple", "endpoint"))
val generated = OpenAPIGen.fromEndpoints(
"Simple Endpoint",
"1.0",
simpleEndpoint.tag("simple", "endpoint") ?? Doc.p("some extra doc"),
)
val json = toJsonAst(generated)
val expectedJson = """{
| "openapi" : "3.1.0",
Expand All @@ -261,7 +265,7 @@ object OpenAPIGenSpec extends ZIOSpecDefault {
| },
| "paths" : {
| "/static/{id}/{uuid}/{name}" : {
| "description" : "- simple\n- endpoint\n",
| "description" : "some extra doc\n\n- simple\n- endpoint\n",
| "get" : {
| "tags" : [
| "simple",
Expand Down
10 changes: 6 additions & 4 deletions zio-http/shared/src/main/scala/zio/http/codec/Doc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ sealed trait Doc { self =>

def +(that: Doc): Doc =
(self, that) match {
case (self, that) if self.isEmpty => that
case (self, that) if that.isEmpty => self
case _ => Doc.Sequence(self, that)
case (self, that) if self.isEmpty => that
case (self, that) if that.isEmpty => self
case _ if tags.isEmpty && that.tags.isEmpty => Doc.Sequence(self, that)
case _ => Doc.Sequence(self, that).tag(self.tags ++ that.tags)
}

def isEmpty: Boolean =
Expand Down Expand Up @@ -148,7 +149,8 @@ sealed trait Doc { self =>
case Doc.Raw(_, docType) =>
throw new IllegalArgumentException(s"Unsupported raw doc type: $docType")

case Doc.Tagged(_, _) =>
case Doc.Tagged(doc, _) =>
render(doc, indent)

}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,48 @@ final case class OpenAPI(
.groupBy(_._1)
.map { case (path, pathItems) =>
val pathItem = pathItems.map(_._2).reduce { (i, j) =>
var docI = Doc.empty
var docJ = Doc.empty
var get = i.get
var put = i.put
var post = i.post
var delete = i.delete
var options = i.options
var head = i.head
var patch = i.patch
var trace = i.trace

if (
get.isDefined || put.isDefined || post.isDefined || delete.isDefined || options.isDefined || head.isDefined || patch.isDefined || trace.isDefined
) {
docI = i.description.getOrElse(Doc.empty)
}
if (
(get.isEmpty && j.get.isDefined) || (put.isEmpty && j.put.isDefined) || (post.isEmpty && j.post.isDefined) || (delete.isEmpty && j.delete.isDefined) || (options.isEmpty && j.options.isDefined) || (head.isEmpty && j.head.isDefined) || (patch.isEmpty && j.patch.isDefined) || (trace.isEmpty && j.trace.isDefined)
) {
docJ = j.description.getOrElse(Doc.empty)
}
get = get.orElse(j.get)
put = put.orElse(j.put)
post = post.orElse(j.post)
delete = delete.orElse(j.delete)
options = options.orElse(j.options)
head = head.orElse(j.head)
patch = patch.orElse(j.patch)
trace = trace.orElse(j.trace)

i.copy(
get = i.get.orElse(j.get),
put = i.put.orElse(j.put),
post = i.post.orElse(j.post),
delete = i.delete.orElse(j.delete),
options = i.options.orElse(j.options),
head = i.head.orElse(j.head),
patch = i.patch.orElse(j.patch),
trace = i.trace.orElse(j.trace),
get = get,
put = put,
post = post,
delete = delete,
options = options,
head = head,
patch = patch,
trace = trace,
description = Some(docI + docJ).filter(!_.isEmpty),
servers = i.servers ++ j.servers,
parameters = i.parameters ++ j.parameters,
)
}
(path, pathItem)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -538,8 +538,7 @@ object OpenAPIGen {
val path = buildPath(endpoint.input)
val method0 = method(inAtoms.method)
// Endpoint has only one doc. But open api has a summery and a description
val pathItem = OpenAPI.PathItem.empty
.copy(description = Some(endpoint.documentation + endpoint.input.doc.getOrElse(Doc.empty)).filter(!_.isEmpty))
val pathItem = OpenAPI.PathItem.empty.copy(description = Some(endpoint.documentation).filter(!_.isEmpty))
val pathItemWithOp = method0 match {
case Method.OPTIONS => pathItem.addOptions(operation(endpoint))
case Method.GET => pathItem.addGet(operation(endpoint))
Expand Down Expand Up @@ -581,7 +580,7 @@ object OpenAPIGen {
}

def operation(endpoint: Endpoint[_, _, _, _, _]): OpenAPI.Operation = {
val maybeDoc = Some(endpoint.documentation + pathDoc).filter(!_.isEmpty)
val maybeDoc = Some(pathDoc).filter(!_.isEmpty)
OpenAPI.Operation(
tags = endpoint.tags,
summary = None,
Expand Down

0 comments on commit 13ecf37

Please sign in to comment.