HttpApp Bootstrap

API may change

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 is to help you start an HTTP server with just a few lines of code. This is accomplished just by extending HttpApp and implementing the routes() method. If desired, HttpApp provides different hook methods that can be overridden to change its default behavior.

Minimal Example

The following example shows how to start a server:

Scala
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
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 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 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 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
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 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
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 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 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 reads the default 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
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
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 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 creates its own ActorSystem instance when one is not provided. In case you already created an ActorSystem in your application you can pass it to startServer as illustrated in the following example:

Scala
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
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();

Providing your own Actor System and Settings

HttpApp offers another overloaded startServer method where you can pass, on top of the host and port, your previously created ActorSystem and your custom ServerSettings. You can see an example in the following code snippet:

Scala
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
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 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 can be configured to signal the server termination just by overriding the method waitForShutdownSignal. This method must return a FutureCompletionStage that, when terminated, will shutdown the server.

This following example shows how to override the default termination signal:

Scala
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
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 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’s postServerShutdown method.

Here you can find an example:

Scala
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
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 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.

The source code for this page can be found here.