Migration Guide to and within Akka HTTP 10.2.x

General Notes

See the general compatibility guidelines.

Under these guidelines, minor version updates are supposed to be binary compatible and drop-in replacements for former versions under the condition that user code only uses public, stable, non-deprecated API. Especially libraries should make sure not to depend on deprecated API to be compatible with both 10.1.x and 10.2.x.

If you find an unexpected incompatibility please let us know, so we can check whether the incompatibility is accidental, so we might still be able to fix it.

Akka HTTP 10.1.x -> 10.2.0

10.2.0 will introduce deprecation warnings to every server project because the existing Http.bind* methods have been deprecated and replaced by the new ServerBuild API. To ease the migration pain, we have prepared scalafix rules to automatically rewrite existing code to the new API.

To run those rules, first add scalafix to your project/plugins.sbt:

addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.21")

The in the sbt shell of your project run:

scalafixEnable
set scalacOptions in ThisBuild += "-P:semanticdb:synthetics:on"
scalafixAll dependency:[email protected]:akka-http-scalafix-rules:10.2.0

See also scalafix’s Installation and External Rules documentation.

If your open-source project uses scala-steward it might already automatically run those scalafix migrations and include the changes in its update PR to your repository.

Hiding Materializer

Recent Akka versions introduced a singleton system materializer that can be summoned from an ActorSystem automatically. In many cases, Materializer arguments are now optional and APIs have been simplified to require materializers in fewer places. In fact, most common uses do not require a materializer any more at all.

New ServerBuilder API to create server bindings

To simplify binding servers (and to make it more consistent between Java and Scala), a new ServerBuilderServerBuilder API has been introduced. The most common change needed to bind a server to handle routes will be from:

Scala
// only worked with classic actor system
implicit val system = akka.actor.ActorSystem("TheSystem")
implicit val mat: Materializer = ActorMaterializer()
val route: Route =
  get {
    complete("Hello world")
  }
Http().bindAndHandle(route, "localhost", 8080)
Java
// only worked with classic actor system
akka.actor.ActorSystem system = akka.actor.ActorSystem.create("TheSystem");
Materializer mat = ActorMaterializer.create(system);
Route route = get(() -> complete("Hello World!"));
Http.get(system).bindAndHandle(route.flow(system), ConnectHttp.toHost("localhost", 8080), mat);

to:

Scala
// works with both classic and typed ActorSystem
implicit val system = akka.actor.typed.ActorSystem(Behaviors.empty, "TheSystem")
// or
// implicit val system = akka.actor.ActorSystem("TheSystem")

// materializer not needed any more

val route: Route =
  get {
    complete("Hello world")
  }
Http().newServerAt("localhost", 8080).bind(route)
Java
// works with classic or typed actor system
akka.actor.typed.ActorSystem system = akka.actor.typed.ActorSystem.create(Behaviors.empty(), "TheSystem");
// or
// akka.actor.ActorSystem system = akka.actor.ActorSystem.create("TheSystem");

// materializer not needed any more

Route route = get(() -> complete("Hello World!"));
Http.get(system).newServerAt("localhost", 8080).bind(route);

Scala 2.11 support dropped

Almost three years after the release of Scala 2.11.12, support for Scala 2.11 has been dropped following the example of Akka 2.6. Akka HTTP 10.1.x which still supports Scala 2.11 will be supported for a while.

HttpRequest.copy / HttpResponse.copy deprecated in favor of withXYZ methods

HttpRequest and HttpResponse have been converted from case classes to regular classes already a while ago. This was necessary to keep being able to make binary compatible changes to the API. So far, we kept the copy methods available but, like all methods with default parameters, these started to become a liability as well. In 10.2.0, the copy methods are now deprecated in favor of the more explicit withXYZ methods. This will help us to evolve those APIs in the future (as unfortunate it is that the idiomatic Scala way of case classes / default arguments is not an option because of our compatibility constraints).

HTTP/2 support requires JDK 8 update 252 or later

JVM support for ALPN has been backported to JDK 8u252 which is now widely available. Support for using the Jetty ALPN agent has been dropped in 10.2.0. HTTP/2 support therefore now requires to be run on JVM >= 8u252.

Scalatest dependency upgraded to 3.1.0

The Scalatest dependency for akka-http-testkit was upgraded to version 3.1.0. This version is incompatible with previous versions. This is relevant for user code if it uses methods from ScalatestUtils (which are in scope if your test extends from ScalaTestRouteTest). In this case, the project itself needs to be updated to use Scalatest >= 3.1.0.

Providing route settings, exception and rejection handling

Previously, the implicit conversion route2HandlerFlow that turns a Route into a Flow[HttpRequest, HttpResponse] allowed implicitly passing in Routing settings, Parser settings, custom Materializer, RoutingLog or ExecutionContext, and the RejectionHandler/ExceptionHandler to use.

This has been simplified to use system defaults by default and to require explicit code if you want to change those defaults:

In RouteTest (scaladsl)

Similarly, RouteTestRouteTest no longer automatically picks up such implicit values, and you can use the same approach to explicitly set them instead.

Strict query strings

In 10.1.x, while parsing the query string of a URI, characters were accepted that are not allowed according to RFC 3986, even when parsing.uri-parsing-mode was set to the default value of strict. Parsing such URIs will now fail in strict mode. If you want to allow such characters in incoming URIs, set parsing.uri-parsing-mode to relaxed, in which case these characters will be percent-encoded automatically.

Transparent HEAD requests now disabled by default

Prior to 10.2.0, when a client would perform a HEAD request, by default Akka HTTP would call the GET route but discard the body. This can save bandwidth in some cases, but is also counter-intuitive when you actually want to explicitly handle HEAD requests, and may increase resource usage in cases where the logic behind the GET request is heavy. For this reason we have changed the default value of akka.http.server.transparent-head-requests to off, making this feature opt-in.

Server-side HTTP pipelining now disabled by default

HTTP pipelining is now disabled by default. It is not used commonly by clients because it suffers from head-of-line blocking. It is recommended to use pooled connections or HTTP/2 instead.

HTTP pipelining is still supported and can be re-enabled by setting pipelining-limit = n with a value of n > 1.

X-Real-Ip now takes precedence over Remote-Address in extractClientIP

The extractClientIP now returns the value of the X-Real-Ip header when both anX-Real-Ip and a Remote-Address header is available. This directive provides a ‘best guess’ of the client IP, but in a way that allows any client to provide this address in the header. For this reason you should never trust this value for security purposes.

When you need a secure way to get the client IP, use the AttributeKeys.remoteAddressAttributeKeys.remoteAddress attribute, or use the specific headers which are known to be set correctly by the infrastructure you do trust.

max-content-length

The max-content-length setting can no longer be set on akka.http.parsing, and instead must now be set explicitly on akka.http.client.parsing and/or akka.http.server.parsing. The default for akka.http.client.parsing.max-content-length has been changed from 8m to infinite.

Removal of legacy host connection pool

The legacy host connection pool is the original client pool implementation from the beginnings of Akka HTTP backing Http().singleRequest and other client APIs. During the 10.0.x development the pool was reimplemented and could be used in an opt-in fashion. Since 10.1.0, this new pool implementation has been the default. With 10.2.0 we took the opportunity to remove the old pool implementation. The setting akka.http.host-connection-pool.pool-implementation has been removed as well as its code representation in ConnectionPoolSettings.

headerValueByType (scaladsl)

When using the Scala DSL, invoking headerValueByType and optionalHeaderValueByType by just its generic parameter, like headerValueByType[Origin](), uses a Scala feature called ‘argument adaptation’ that is planned to go away in a future value of Scala. While you could earlier work around this by writing headerValueByType[Origin](()), we have now deprecated this as well and you are encouraged to use the companion object instead: headerValueByType(Origin). For headers that do not have a companion object, you can headerValueByType(classOf[UpgradeToWebSocket]).

parameters / formFields (scaladsl)

The parameters and the formFields directives used to rely on the ‘magnet pattern’. Unfortunately, for the case where you would match multiple parameters, the pattern relied on a Scala feature called ‘argument adaptation’ which is planned to go away in a future version of Scala.

Earlier, you would have to work around this by including double parentheses, like this (same for formFields):

parameters(("a".as[Int], "b".as[Int]))

We have changed the implementation of the directives in a way that is binary compatible and source compatible, with one exception: previously, <name>.requiredValue would match and check a parameter, but it would not be extracted by the directive. From 10.2.0 forward it will be extracted by the directive even when it is required.

This means when in the past you had:

parameter("nose".requiredValue("large")) { complete("Ok!") }

You would now have

parameter("nose".requiredValue("large")) { _ => complete("Ok!") }

This is especially relevant when you were combining parameters directives with other directives using |: since the output types of the directives on both ‘sides’ of the | need to be equal, where you previously might have had:

(post | parameter("method".requiredValue("post"))) { complete("POST") }

You will now have to explicitly discard the parameter value:

(post | parameter("method".requiredValue("post")).tmap(_ => ())) { complete("POST") }

Coding infrastructure is now internal

Previously, the coding infrastructure has been mostly public, exposing API that was never intended to be public. Most of the existing classes have now been marked as internal and deprecated. This will allow us to remove the coding infrastructure from akka-http itself in the future and use implementations provided by akka-stream directly.

Only parts of Encoder, Decoder, and Coder are still public. Predefined coders that have been available as e.g. akka.http.scaladsl.coding.Gzip are now available as scaladsl.coding.Coders.Gzip, Coders.Deflate, and Coders.NoCoding. Coding directives that use the default coding setup, like encodeResponse and decodeRequest continue to work without changes necessary.

Configuring HTTPS connections

Akka HTTP no longer uses the HTTPS configuration configured with ssl-config by default. Instead, it will use the JRE defaults for client connections. For server connections you should create a HttpsConnectionContextHttpsConnectionContext with the relevant configuration.

Previously, the SSL configuration was constructed based on the parameters you pass to HttpsConnectionContextHttpsConnectionContext and the logic and configuration used by the ssl-config library. This was because back then the default JDK SSL configuration was a bad match for HTTP connections. Nowadays, however, the JDK defaults are much better and the use of ssl-config makes the configuration hard to reason about.

For this reason, we have deprecated the ssl-config-based APIs, and now provide ConnectionContext.httpsServerConnectionContext.httpsServer and ConnectionContext.httpsClientConnectionContext.httpsClient that will use the JDK defaults. There is also a ConnectionContext.httpsConnectionContext.https where you can provide your own logic for creating SSLEngine instances. When using this more low-level API, remember it is up to you to set the SSLEngine ‘mode’ (client or server), and further configuration such as enabling SNI and hostname verification features when needed.

List of deprecated and deleted APIs

Deprecated APIs

javadsl:

  • static akka.http.javadsl.ConnectionContext.https
  • most getters of akka.http.javadsl.ConnectionContext
  • akka.http.javadsl.Http.bind
  • akka.http.javadsl.Http.bindAndHandle
  • akka.http.javadsl.Http.bindAndHandleSync
  • akka.http.javadsl.Http.bindAndHandleAsync
  • akka.http.javadsl.Http.defaultServerHttpContext
  • akka.http.javadsl.Http.setDefaultServerHttpContext
  • akka.http.javadsl.Http.createServerHttpsContext
  • akka.http.javadsl.Http.createClientHttpsContext
  • akka.http.javadsl.Http.createDefaultClientHttpsContext
  • akka.http.javadsl.model.ws.UpgradeToWebSocket
  • akka.http.javadsl.server.HttpApp
  • akka.http.javadsl.settings.ParserSettings.create
  • akka.http.javadsl.settings.ServerSettings.getRemoteAddressHeader
  • akka.http.javadsl.settings.ServerSettings.getWebsocketRandomFactory
  • akka.http.javadsl.settings.ServerSettings.withWebsocketRandomFactory
  • akka.http.javadsl.server.directives.WebSocketDirectives.extractUpgradeToWebSocket

scaladsl:

  • most of akka.http.scaladsl.ConnectionContext
  • akka.http.scaladsl.HttpExt.bind
  • akka.http.scaladsl.HttpExt.bindAndHandle
  • akka.http.scaladsl.HttpExt.bindAndHandleSync
  • akka.http.scaladsl.HttpExt.bindAndHandleAsync
  • akka.http.scaladsl.Http.defaultServerHttpContext
  • akka.http.scaladsl.Http.setDefaultServerHttpContext
  • akka.http.scaladsl.Http.createClientHttpsContext
  • akka.http.scaladsl.Http.createDefaultClientHttpsContext
  • akka.http.scaladsl.model.HttpCookie.copy
  • akka.http.scaladsl.model.HttpCookie.unapply
  • akka.http.scaladsl.model.HttpRequest.copy
  • akka.http.scaladsl.model.HttpResponse.copy
  • akka.http.scaladsl.model.headers.Remote-Address
  • akka.http.scaladsl.model.ws.UpgradeToWebSocket
  • akka.http.scaladsl.server.HttpApp
  • akka.http.scaladsl.settings.ParserSettings.apply
  • akka.http.scaladsl.settings.ServerSettings.remoteAddressHeader
  • akka.http.scaladsl.settings.ServerSettings.getWebsocketRandomFactory
  • akka.http.scaladsl.settings.ServerSettings.withWebsocketRandomFactory
  • akka.http.scaladsl.coding.Deflate
  • akka.http.scaladsl.coding.DeflateCompressor
  • akka.http.scaladsl.coding.StreamDecoder
  • akka.http.scaladsl.coding.Encoder.encode(ByteString): ByteString
  • akka.http.scaladsl.coding.Encoder.newCompressor
  • akka.http.scaladsl.coding.Encoder.newEncodeTransformer
  • akka.http.scaladsl.coding.Compressor
  • akka.http.scaladsl.coding.Gzip
  • akka.http.scaladsl.coding.NoCoding
  • akka.http.scaladsl.server.Route.asyncHandler
  • akka.http.scaladsl.server.directives.FormFieldDirectives.FieldMagnet
  • akka.http.scaladsl.server.directives.FormFieldDirectives.FieldDef
  • akka.http.scaladsl.server.directives.FormFieldDirectives.FieldDefAux
  • akka.http.scaladsl.server.directives.HeaderDirectives.headerValueByName
  • akka.http.scaladsl.server.directives.HeaderDirectives.optionalHeaderValueByName
  • akka.http.scaladsl.server.directives.HeaderDirectives.fromUnitForModeledCustomHeader
  • akka.http.scaladsl.server.directives.HeaderDirectives.fromUnitNormalHeader
  • akka.http.scaladsl.server.directives.WebSocketDirectives.extractUpgradeToWebSocket

Deleted APIs (or overloads)

  • some akka.http.javadsl.Http method overloads with a materializer parameter (like singleRequest, superPool)
  • akka.http.javadsl.HostConnectionPool.shutdown
  • akka.http.javadsl.model.HttpMethod.getRequestEntityAcceptance
  • akka.http.javadsl.model.HttpMethods.createCustom
  • akka.http.javadsl.settings.ConnectionPoolSettings.getTransport
  • akka.http.javadsl.*ConnectionContext.getDefaultPort
  • some akka.http.scaladsl.HttpExt method overloads with a materializer parameter (like singleRequest, superPool)

  • akka.http.scaladsl.Http#HostConnectionPool.shutdown
  • akka.http.scaladsl.HttpExt.outgoingConnectionUsingTransport
  • akka.http.scaladsl.UseHttp2 and related methods in ConnectionContext and ConnectHttp
  • akka.http.scaladsl.model.HttpMethod.getRequestEntityAcceptance
Found an error in this documentation? The source code for this page can be found here. Please feel free to edit and contribute a pull request.