diff --git a/akka-javasdk/src/main/java/akka/javasdk/http/RequestContext.java b/akka-javasdk/src/main/java/akka/javasdk/http/RequestContext.java index 528820b38..76837472f 100644 --- a/akka-javasdk/src/main/java/akka/javasdk/http/RequestContext.java +++ b/akka-javasdk/src/main/java/akka/javasdk/http/RequestContext.java @@ -5,11 +5,15 @@ package akka.javasdk.http; import akka.annotation.DoNotInherit; +import akka.http.javadsl.model.HttpHeader; import akka.javasdk.Context; import akka.javasdk.JwtClaims; import akka.javasdk.Principals; import akka.javasdk.Tracing; +import java.util.List; +import java.util.Optional; + /** * Not for user extension, can be injected as constructor parameter into HTTP endpoint components or * accessible from {@link AbstractHttpEndpoint#requestContext()} if the endpoint class extends @@ -28,6 +32,15 @@ public interface RequestContext extends Context { /** @return The JWT claims, if any, associated with this request. */ JwtClaims getJwtClaims(); + /** + * @return A header with the given name (case ignored) if present in the current request, + * Optional.empty() if not. + */ + Optional requestHeader(String headerName); + + /** @return A list with all the headers of the current request */ + List allRequestHeaders(); + /** Access to tracing for custom app specific tracing. */ Tracing tracing(); } diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/SdkRunner.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/SdkRunner.scala index 1b169b552..9e8bf7fa3 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/SdkRunner.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/SdkRunner.scala @@ -8,7 +8,6 @@ import java.lang.reflect.Constructor import java.lang.reflect.InvocationTargetException import java.lang.reflect.Method import java.util.concurrent.CompletionStage - import scala.annotation.nowarn import scala.concurrent.ExecutionContext import scala.concurrent.Future @@ -18,10 +17,10 @@ import scala.jdk.FutureConverters._ import scala.jdk.OptionConverters.RichOptional import scala.reflect.ClassTag import scala.util.control.NonFatal - import akka.Done import akka.actor.typed.ActorSystem import akka.annotation.InternalApi +import akka.http.javadsl.model.HttpHeader import akka.http.scaladsl.model.headers.RawHeader import akka.javasdk.BuildInfo import akka.javasdk.DependencyProvider @@ -96,6 +95,10 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import org.slf4j.event.Level +import java.util +import java.util.Optional +import scala.jdk.OptionConverters.RichOption + /** * INTERNAL API */ @@ -667,6 +670,14 @@ private final class Sdk( "There are no JWT claims defined but trying accessing the JWT claims. The class or the method needs to be annotated with @JWT.") } + override def requestHeader(headerName: String): Optional[HttpHeader] = + // Note: force cast to Java header model + context.requestHeaders.header(headerName).asInstanceOf[Option[HttpHeader]].toJava + + override def allRequestHeaders(): util.List[HttpHeader] = + // Note: force cast to Java header model + context.requestHeaders.allHeaders.asInstanceOf[Seq[HttpHeader]].asJava + override def tracing(): Tracing = new SpanTracingImpl(context.openTelemetrySpan, sdkTracerFactory) } val instance = wiredInstance(httpEndpointClass) { diff --git a/docs/src/modules/java/pages/http-endpoints.adoc b/docs/src/modules/java/pages/http-endpoints.adoc index 99add3332..1681c34d2 100644 --- a/docs/src/modules/java/pages/http-endpoints.adoc +++ b/docs/src/modules/java/pages/http-endpoints.adoc @@ -244,3 +244,17 @@ include::example$doc-snippets/src/main/java/com/example/api/ExampleEndpoint.java <1> Accept the materializer and keep it in a field <2> Make sure to discard the request body when failing <3> Or collect the bytes into memory + + + === Accessing request headers === + + Accessing request headers is done through the link:_attachments/api/akka/javasdk/http/RequestContext.html[RequestContext] methods `requestHeader(String headerName)` and `allRequestHeaders()`. + + By letting the endpoint extend link:_attachments/api/akka/javasdk/http/AbstractHttpEndpoint.html[AbstractHttpEndpoint] request context is available through the method `requestContext()`. + + [source,java] + .{sample-base-url}/doc-snippets/src/main/java/com/example/api/ExampleEndpoint.java[ExampleEndpoint.java] + ---- + include::example$doc-snippets/src/main/java/com/example/api/ExampleEndpoint.java[tag=header-access] + ---- + <1> `requestHeader(headerName)` returns an `Optional` which is empty if the header was not present. \ No newline at end of file