Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async api example rendering bugfix #3936

Merged
merged 1 commit into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
package sttp.tapir.docs.asyncapi

import sttp.apispec._
import sttp.apispec.asyncapi.MessageExample
import sttp.tapir.{Codec, EndpointIO}
import sttp.ws.WebSocketFrame

private[asyncapi] object ExampleConverter {
def convertExamples[T](c: Codec[WebSocketFrame, T, _], examples: List[EndpointIO.Example[T]]): List[ExampleValue] = {
def convertExamples[T](c: Codec[WebSocketFrame, T, _], examples: List[EndpointIO.Example[T]]): List[MessageExample] = {
examples
.flatMap { example =>
val exampleValue = c.encode(example.value) match {
case WebSocketFrame.Text(payload, _, _) => Some(payload)
case WebSocketFrame.Binary(_, _, _) => None
case _: WebSocketFrame.Control => None
c.encode(example.value) match {
case WebSocketFrame.Text(payload, _, _) =>
Some(MessageExample(headers = None, Some(ExampleSingleValue(payload)), example.name, example.summary))
case WebSocketFrame.Binary(_, _, _) => None
case _: WebSocketFrame.Control => None
}

exampleValue.map(ExampleSingleValue)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ private[asyncapi] class MessagesForEndpoints(tschemaToASchema: TSchemaToASchema,
)

private def message[T](ci: CodecWithInfo[T]): Message = {
val convertedExamples = ExampleConverter.convertExamples(ci.codec, ci.info.examples)
SingleMessage(
None,
Some(Right(tschemaToASchema(ci.codec))),
Expand All @@ -53,7 +52,7 @@ private[asyncapi] class MessagesForEndpoints(tschemaToASchema: TSchemaToASchema,
Nil,
None,
Nil,
convertedExamples.map(example => Map("payload" -> (example :: Nil))),
ExampleConverter.convertExamples(ci.codec, ci.info.examples),
Nil
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
asyncapi: 2.6.0
info:
title: The fruit basket
version: '0.1'
channels:
/fruit:
subscribe:
operationId: onFruit
message:
$ref: '#/components/messages/integer'
publish:
operationId: sendFruit
message:
$ref: '#/components/messages/Fruit'
bindings:
ws:
method: GET
components:
schemas:
Fruit:
title: Fruit
type: object
required:
- f
properties:
f:
type: string
messages:
Fruit:
payload:
$ref: '#/components/schemas/Fruit'
contentType: application/json
examples:
- payload:
f: apple
name: Apple
summary: Sample representation of apple
integer:
payload:
type: integer
format: int32
contentType: application/json
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,12 @@ components:
contentType: application/json
examples:
- payload:
- f: apple
f: apple
integer:
payload:
type: integer
format: int32
contentType: application/json
examples:
- payload:
- 10
- payload:
- 42
- payload: 10
- payload: 42
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import sttp.apispec.asyncapi.{Info, Server}
import sttp.capabilities.akka.AkkaStreams
import sttp.model.HeaderNames
import sttp.apispec.asyncapi.circe.yaml._
import sttp.tapir.EndpointIO.Example
import sttp.tapir.Schema.SName
import sttp.tapir._
import sttp.tapir.docs.asyncapi.AsyncAPIDocsOptions.defaultOperationIdGenerator
Expand All @@ -16,6 +17,7 @@ import sttp.tapir.docs.apispec.DocsExtension
import sttp.tapir.tests.data.{Fruit, FruitAmount}

import scala.io.Source
import scala.util.chaining.scalaUtilChainingOps

class VerifyAsyncAPIYamlTest extends AnyFunSuite with Matchers {

Expand Down Expand Up @@ -125,6 +127,23 @@ class VerifyAsyncAPIYamlTest extends AnyFunSuite with Matchers {
actualYamlNoIndent shouldBe expectedYaml
}

test("should include example name and summary") {
val e = endpoint
.in("fruit")
.out(
webSocketBody[Fruit, CodecFormat.Json, Int, CodecFormat.Json](AkkaStreams)
// TODO: missing `RequestInfo.example(example: EndpointIO.Example)` and friends
.pipe(e => e.copy(requestsInfo = e.requestsInfo.example(Example.of(Fruit("apple")).name("Apple").summary("Sample representation of apple"))))
)

val expectedYaml = loadYaml("expected_json_example_name_summary.yml")

val actualYaml = AsyncAPIInterpreter().toAsyncAPI(e, "The fruit basket", "0.1").toYaml
val actualYamlNoIndent = noIndentation(actualYaml)

actualYamlNoIndent shouldBe expectedYaml
}

test("should include required indicator for non optional inputs") {
val e = endpoint
.in("fruit" / query[Int]("limit").and(query[Option[Int]]("offset")))
Expand Down
2 changes: 1 addition & 1 deletion project/Versions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ object Versions {
val sttp = "3.9.7"
val sttpModel = "1.7.11"
val sttpShared = "1.3.19"
val sttpApispec = "0.10.0"
val sttpApispec = "0.11.0"
val akkaHttp = "10.2.10"
val akkaStreams = "2.6.20"
val pekkoHttp = "1.0.1"
Expand Down
Loading