HttpApp Bootstrap
This is experimental and the API is subjected to change in future releases of Akka HTTP. For further information about this marker, see The @DoNotInherit and @ApiMayChange markers in the Akka documentation.
Introduction
The objective of HttpApp
HttpApp
is to help you start an HTTP server with just a few lines of code. This is accomplished just by extending HttpApp
HttpApp
and implementing the routes()
method. If desired, HttpApp
HttpApp
provides different hook methods that can be overridden to change its default behavior.
Please note that HttpApp
HttpApp
is not the canonical way of starting an akka-http server. It is a tool to get up and running fast. For integrating into already existing Akka applications that already bring their ActorSystem
ActorSystem
using Http.bindAndHandle
(which is also just a single line of code) is recommended over using HttpApp
HttpApp
.
Minimal Example
The following example shows how to start a server:
- Scala
-
source
import akka.http.scaladsl.model.{ ContentTypes, HttpEntity } import akka.http.scaladsl.server.HttpApp import akka.http.scaladsl.server.Route // Server definition object WebServer extends HttpApp { override def routes: Route = path("hello") { get { complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>")) } } } // Starting the server WebServer.startServer("localhost", 8080)
- Java
-
source
import akka.Done; import akka.actor.ActorSystem; import akka.http.javadsl.server.HttpApp; import akka.http.javadsl.server.Route; import java.util.Optional; import java.util.concurrent.*; // Server definition class MinimalHttpApp extends HttpApp { @Override protected Route routes() { return path("hello", () -> get(() -> complete("<h1>Say hello to akka-http</h1>") ) ); } } // Starting the server final MinimalHttpApp myServer = new MinimalHttpApp(); myServer.startServer("localhost", 8080);
Firstly we define an object
(it can also be a class
)a class
that extends HttpApp
HttpApp
and we just implement the routes this server will handle. After that, we can start a server just by providing a host
and a port
. Calling startServer
blocks the current thread until the server is signaled for termination. The default behavior of HttpApp
HttpApp
is to start a server, and shut it down after ENTER
is pressed. When the call to startServer
returns the server is properly shut down.
Reacting to Bind Failures
HttpApp
HttpApp
provides different hooks that will be called after a successful and unsuccessful initialization. For example, the server might not start due to the port being already in use, or because it is a privileged one.
Here you can see an example server that overrides the postHttpBindingFailure
hook and prints the error to the console (this is also the default behavior)
- Scala
-
source
import akka.http.scaladsl.Http import akka.http.scaladsl.model._ import akka.http.scaladsl.server.HttpApp import akka.http.scaladsl.server.Route import akka.http.scaladsl.settings.ServerSettings import com.typesafe.config.ConfigFactory // Server definition object WebServer extends HttpApp { override def routes: Route = path("hello") { get { complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>")) } } override protected def postHttpBinding(binding: Http.ServerBinding): Unit = { super.postHttpBinding(binding) val sys = systemReference.get() sys.log.info(s"Running on [${sys.name}] actor system") } override protected def postHttpBindingFailure(cause: Throwable): Unit = { println(s"The server could not be started due to $cause") } } // Starting the server WebServer.startServer("localhost", 80, ServerSettings(ConfigFactory.load))
- Java
-
source
import akka.Done; import akka.actor.ActorSystem; import akka.http.javadsl.server.HttpApp; import akka.http.javadsl.server.Route; import akka.http.javadsl.settings.ServerSettings; import akka.http.javadsl.ServerBinding; import com.typesafe.config.ConfigFactory; import java.util.Optional; import java.util.concurrent.*; // Server definition class FailBindingOverrideHttpApp extends HttpApp { @Override protected Route routes() { return path("hello", () -> get(() -> complete("<h1>Say hello to akka-http</h1>") ) ); } @Override protected void postHttpBinding(ServerBinding binding) { super.postHttpBinding(binding); final ActorSystem sys = systemReference.get(); sys.log().info("Running on [" + sys.name() + "] actor system"); } @Override protected void postHttpBindingFailure(Throwable cause) { System.out.println("I can't bind!"); } } // Starting the server final FailBindingOverrideHttpApp myServer = new FailBindingOverrideHttpApp(); myServer.startServer("localhost", 80, ServerSettings.create(ConfigFactory.load()));
So if the port 80
would be already taken by another app, the call to startServer
returns immediately and the postHttpBindingFailure
hook will be called.
Providing your own Server Settings
HttpApp
HttpApp
reads the default ServerSettings
ServerSettings
when one is not provided. In case you want to provide different settings, you can simply pass it to startServer
as illustrated in the following example:
- Scala
-
source
import akka.http.scaladsl.model.{ ContentTypes, HttpEntity } import akka.http.scaladsl.server.HttpApp import akka.http.scaladsl.server.Route import akka.http.scaladsl.settings.ServerSettings import com.typesafe.config.ConfigFactory // Server definition object WebServer extends HttpApp { override def routes: Route = path("hello") { get { complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>")) } } } // Creating own settings val settings = ServerSettings(ConfigFactory.load).withVerboseErrorMessages(true) WebServer.startServer("localhost", 8080, settings)
- Java
-
source
import akka.Done; import akka.actor.ActorSystem; import akka.http.javadsl.server.HttpApp; import akka.http.javadsl.server.Route; import akka.http.javadsl.settings.ServerSettings; import akka.http.javadsl.ServerBinding; import com.typesafe.config.ConfigFactory; import java.util.Optional; import java.util.concurrent.*; // Server definition class MinimalHttpApp extends HttpApp { @Override protected Route routes() { return path("hello", () -> get(() -> complete("<h1>Say hello to akka-http</h1>") ) ); } } // Starting the server final MinimalHttpApp myServer = new MinimalHttpApp(); final ServerSettings settings = ServerSettings.create(ConfigFactory.load()).withVerboseErrorMessages(true); myServer.startServer("localhost", 8080, settings);
Providing your own Actor System
HttpApp
HttpApp
creates its own ActorSystem
ActorSystem
instance when one is not provided. In case you already created an ActorSystem
ActorSystem
in your application you can pass it to startServer
as illustrated in the following example:
- Scala
-
source
import akka.actor.ActorSystem import akka.http.scaladsl.model._ import akka.http.scaladsl.server.HttpApp import akka.http.scaladsl.server.Route // Server definition object WebServer extends HttpApp { override def routes: Route = path("hello") { get { complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>")) } } } // Starting the server val system = ActorSystem("ownActorSystem") WebServer.startServer("localhost", 8080, system) system.terminate()
- Java
-
source
import akka.Done; import akka.actor.ActorSystem; import akka.http.javadsl.server.HttpApp; import akka.http.javadsl.server.Route; import java.util.Optional; import java.util.concurrent.*; // Server definition class MinimalHttpApp extends HttpApp { @Override protected Route routes() { return path("hello", () -> get(() -> complete("<h1>Say hello to akka-http</h1>") ) ); } } // Starting the server final ActorSystem system = ActorSystem.apply("myOwn"); new MinimalHttpApp().startServer("localhost", 8080, system); // ActorSystem is not terminated after server shutdown // It must be manually terminated system.terminate();
When you provide your own ActorSystem
ActorSystem
you are responsible for terminating it. For more fine-grained control over the shutdown of various parts of the application, take a look at Coordinated ShutdownCoordinated Shutdown extension which is available since Akka 2.5.0.
Providing your own Actor System and Settings
HttpApp
HttpApp
offers another overloaded startServer
method where you can pass, on top of the host
and port
, your previously created ActorSystem
ActorSystem
and your custom ServerSettings
ServerSettings
. You can see an example in the following code snippet:
- Scala
-
source
import akka.actor.ActorSystem import akka.http.scaladsl.model._ import akka.http.scaladsl.server.HttpApp import akka.http.scaladsl.server.Route import akka.http.scaladsl.settings.ServerSettings import com.typesafe.config.ConfigFactory // Server definition object WebServer extends HttpApp { override def routes: Route = path("hello") { get { complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>")) } } } // Starting the server val system = ActorSystem("ownActorSystem") val settings = ServerSettings(ConfigFactory.load).withVerboseErrorMessages(true) WebServer.startServer("localhost", 8080, settings, system) system.terminate()
- Java
-
source
import akka.Done; import akka.actor.ActorSystem; import akka.http.javadsl.server.HttpApp; import akka.http.javadsl.server.Route; import akka.http.javadsl.settings.ServerSettings; import akka.http.javadsl.ServerBinding; import com.typesafe.config.ConfigFactory; import java.util.Optional; import java.util.concurrent.*; // Server definition class MinimalHttpApp extends HttpApp { @Override protected Route routes() { return path("hello", () -> get(() -> complete("<h1>Say hello to akka-http</h1>") ) ); } } // Starting the server final ActorSystem system = ActorSystem.apply("myOwn"); final ServerSettings settings = ServerSettings.create(ConfigFactory.load()).withVerboseErrorMessages(true); new MinimalHttpApp().startServer("localhost", 8080, settings, system); // ActorSystem is not terminated after server shutdown // It must be manually terminated system.terminate();
Overriding Termination Signal
As already described previously, the default trigger that shuts down the server is pressing ENTER
. For simple examples this is sufficient, but for bigger applications this is, most probably, not what you want to do. HttpApp
HttpApp
can be configured to signal the server termination just by overriding the method waitForShutdownSignal
. This method must return a Future
CompletionStage
that, when terminated, will shutdown the server.
This following example shows how to override the default termination signal:
- Scala
-
source
import akka.Done import akka.actor.ActorSystem import akka.http.scaladsl.model._ import akka.http.scaladsl.server.HttpApp import akka.pattern import akka.http.scaladsl.server.Route import akka.http.scaladsl.settings.ServerSettings import com.typesafe.config.ConfigFactory import scala.concurrent.duration._ import scala.concurrent.{ ExecutionContext, Future } import scala.language.postfixOps // Server definition object WebServer extends HttpApp { override def routes: Route = path("hello") { get { complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>")) } } override def waitForShutdownSignal(actorSystem: ActorSystem)(implicit executionContext: ExecutionContext): Future[Done] = { pattern.after(5 seconds, actorSystem.scheduler)(Future.successful(Done)) } } // Starting the server WebServer.startServer("localhost", 8080, ServerSettings(ConfigFactory.load))
- Java
-
source
import akka.Done; import akka.actor.ActorSystem; import akka.http.javadsl.server.HttpApp; import akka.http.javadsl.server.Route; import akka.http.javadsl.settings.ServerSettings; import akka.http.javadsl.ServerBinding; import com.typesafe.config.ConfigFactory; import java.util.Optional; import java.util.concurrent.*; import scala.concurrent.duration.Duration; import scala.runtime.BoxedUnit; import static akka.pattern.PatternsCS.after; // Server definition class SelfDestroyingHttpApp extends HttpApp { @Override protected Route routes() { return path("hello", () -> get(() -> complete("<h1>Say hello to akka-http</h1>") ) ); } @Override protected CompletionStage<Done> waitForShutdownSignal(ActorSystem system) { return after(Duration.apply(5, TimeUnit.SECONDS), system.scheduler(), system.dispatcher().prepare(), CompletableFuture.completedFuture(Done.getInstance())); } } // Starting the server final SelfDestroyingHttpApp myServer = new SelfDestroyingHttpApp(); myServer.startServer("localhost", 8080, ServerSettings.create(ConfigFactory.load()));
Here the termination signal is defined by a future that will be automatically completed after 5 seconds.
Getting Notified on Server Shutdown
There are some cases in which you might want to clean up any resources you were using in your server. In order to do this in a coordinated way, you can override HttpApp
HttpApp
’s postServerShutdown
method.
Here you can find an example:
- Scala
-
source
import akka.Done import akka.actor.ActorSystem import akka.http.scaladsl.model._ import akka.http.scaladsl.server.HttpApp import akka.http.scaladsl.server.Route import akka.http.scaladsl.settings.ServerSettings import scala.util.Try import com.typesafe.config.ConfigFactory // Server definition class WebServer extends HttpApp { override def routes: Route = path("hello") { get { complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>")) } } private def cleanUpResources(): Unit = ??? override def postServerShutdown(attempt: Try[Done], system: ActorSystem): Unit = { cleanUpResources() } } // Starting the server new WebServer().startServer("localhost", 8080, ServerSettings(ConfigFactory.load))
- Java
-
source
import akka.Done; import akka.actor.ActorSystem; import akka.http.javadsl.server.HttpApp; import akka.http.javadsl.server.Route; import akka.http.javadsl.settings.ServerSettings; import akka.http.javadsl.ServerBinding; import com.typesafe.config.ConfigFactory; import java.util.Optional; import java.util.concurrent.*; // Server definition class PostShutdownOverrideHttpApp extends HttpApp { @Override protected Route routes() { return path("hello", () -> get(() -> complete("<h1>Say hello to akka-http</h1>") ) ); } private void cleanUpResources() { } @Override protected void postServerShutdown(Optional<Throwable> failure, ActorSystem system) { cleanUpResources(); } } // Starting the server ActorSystem system = ActorSystem.apply("myActorSystem"); new PostShutdownOverrideHttpApp().startServer("localhost", 8080, ServerSettings.create(system), system);
The postServerShutdown
method will be only called once the server attempt to shutdown has completed. Please notice that in the case that unbind
fails to stop the server, this method will also be called with a failed Try
.exception that this method is called with, may be null. It will be a non-null one only when unbind
fails to stop the server.