Skip to content

Commit d8edbb0

Browse files
authored
Akka HTTP - Return HttpEntity.Strict as-is, do not convert to HttpEntity.Default (#4922)
Some response body types produce `HttpEntity.Strict` by using `HttpEntity` [constructor](https://github.com/softwaremill/tapir/blob/b001ab6ff176e36d5a34d0b5d0609bb9bdf91bf5/server/akka-http-server/src/main/scala/sttp/tapir/server/akkahttp/AkkaToResponseBody.scala#L50). Advantage of `HttpEntity.Strict` is that the entity data (response in this case) is available in a `ByteString`, which makes it easier when one needs to implement a custom Akka HTTP directive that works with the response data, for example a directive for custom response logging. However, `AkkaBodyListener` matched this type as `UniversalEntity`, and by calling `transformDataBytes`, the entity was converted to `HttpEntity.Default`, which stores the data in a `Source`. However, to obtain the response data from a `Source`, one basically needs to run a Future and apply some timeout to make sure that obtaining response data does not take too much time. The purpose of this proposal is to keep `HttpEntity.Strict` as-is when it is available.
1 parent 4e2cc23 commit d8edbb0

File tree

2 files changed

+10
-0
lines changed

2 files changed

+10
-0
lines changed

server/akka-http-server/src/main/scala/sttp/tapir/server/akkahttp/AkkaBodyListener.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ class AkkaBodyListener(implicit ec: ExecutionContext) extends BodyListener[Futur
1616
case ws @ Left(_) => cb(Success(())).map(_ => ws)
1717
case Right(e) if e.isKnownEmpty =>
1818
Future.successful(Right(e)).andThen { case _ => cb(Success(())) }
19+
case Right(e: HttpEntity.Strict) =>
20+
// The advantage of HttpEntity.Strict is that it has the data available in a ByteString, which makes it easier
21+
// to implement custom directives that work with the data, such as custom response logging. Using the case
22+
// below, the entity would be converted to HttpEntity.Default, which has the data available in a Stream.
23+
Future.successful(Right(e)).andThen { case _ => cb(Success(())) }
1924
case Right(e: UniversalEntity) =>
2025
Future.successful(
2126
Right(

server/pekko-http-server/src/main/scala/sttp/tapir/server/pekkohttp/PekkoBodyListener.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ class PekkoBodyListener(implicit ec: ExecutionContext) extends BodyListener[Futu
1616
case ws @ Left(_) => cb(Success(())).map(_ => ws)
1717
case Right(e) if e.isKnownEmpty =>
1818
Future.successful(Right(e)).andThen { case _ => cb(Success(())) }
19+
case Right(e: HttpEntity.Strict) =>
20+
// The advantage of HttpEntity.Strict is that it has the data available in a ByteString, which makes it easier
21+
// to implement custom directives that work with the data, such as custom response logging. Using the case
22+
// below, the entity would be converted to HttpEntity.Default, which has the data available in a Stream.
23+
Future.successful(Right(e)).andThen { case _ => cb(Success(())) }
1924
case Right(e: UniversalEntity) =>
2025
Future.successful(
2126
Right(

0 commit comments

Comments
 (0)