diff --git a/akka-http/pom.xml b/akka-http/pom.xml
new file mode 100644
index 0000000000..05e50d2229
--- /dev/null
+++ b/akka-http/pom.xml
@@ -0,0 +1,48 @@
+
+
+
+ 4.0.0
+ akka-http
+ akka-http
+
+
+ parent-modules
+ com.baeldung
+ 1.0.0-SNAPSHOT
+
+
+
+
+ com.typesafe.akka
+ akka-http_2.12
+ ${akka.http.version}
+
+
+ com.typesafe.akka
+ akka-stream_2.12
+ ${akka.stream.version}
+
+
+ com.typesafe.akka
+ akka-http-jackson_2.12
+ ${akka.http.version}
+
+
+ com.typesafe.akka
+ akka-http-testkit_2.12
+ ${akka.http.version}
+ test
+
+
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 10.0.11
+ 2.5.11
+
+
diff --git a/akka-http/src/main/java/com/baeldung/akkahttp/AkkaHttpServer.java b/akka-http/src/main/java/com/baeldung/akkahttp/AkkaHttpServer.java
new file mode 100644
index 0000000000..03992b6a36
--- /dev/null
+++ b/akka-http/src/main/java/com/baeldung/akkahttp/AkkaHttpServer.java
@@ -0,0 +1,39 @@
+package com.baeldung.akkahttp;
+
+import java.util.concurrent.CompletionStage;
+
+import akka.NotUsed;
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.http.javadsl.ConnectHttp;
+import akka.http.javadsl.Http;
+import akka.http.javadsl.ServerBinding;
+import akka.http.javadsl.model.HttpRequest;
+import akka.http.javadsl.model.HttpResponse;
+import akka.http.javadsl.server.AllDirectives;
+import akka.stream.ActorMaterializer;
+import akka.stream.javadsl.Flow;
+
+public class AkkaHttpServer extends AllDirectives {
+
+ private final UserRoutes userRoutes;
+
+ public AkkaHttpServer(ActorSystem system, ActorRef userRegistryActor) {
+ userRoutes = new UserRoutes(system, userRegistryActor);
+ }
+
+ public static void main(String[] args) throws Exception {
+ ActorSystem system = ActorSystem.create("helloAkkaHttpServer");
+ final ActorMaterializer materializer = ActorMaterializer.create(system);
+
+ ActorRef userActorRef = system.actorOf(UserActor.props(), "userActor");
+
+ AkkaHttpServer app = new AkkaHttpServer(system, userActorRef);
+
+ final Flow routeFlow = app.userRoutes.routes().flow(system, materializer);
+
+ final CompletionStage binding = Http.get(system).bindAndHandle(routeFlow,
+ ConnectHttp.toHost("localhost", 8080), materializer);
+
+ System.out.println("Server is online at http://localhost:8080/");
+ }
\ No newline at end of file
diff --git a/akka-http/src/main/java/com/baeldung/akkahttp/User.java b/akka-http/src/main/java/com/baeldung/akkahttp/User.java
new file mode 100644
index 0000000000..9b5b95ebc1
--- /dev/null
+++ b/akka-http/src/main/java/com/baeldung/akkahttp/User.java
@@ -0,0 +1,30 @@
+package com.baeldung.akkahttp;
+
+/**
+ * User Entity
+ *
+ */
+public class User {
+
+ private final String name;
+ private final String address;
+
+ public User() {
+ this.name = "";
+ this.address = "";
+ }
+
+ public User(String name, String address) {
+ this.name = name;
+ this.address = address;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+}
\ No newline at end of file
diff --git a/akka-http/src/main/java/com/baeldung/akkahttp/UserActor.java b/akka-http/src/main/java/com/baeldung/akkahttp/UserActor.java
new file mode 100644
index 0000000000..f6c7015070
--- /dev/null
+++ b/akka-http/src/main/java/com/baeldung/akkahttp/UserActor.java
@@ -0,0 +1,60 @@
+package com.baeldung.akkahttp;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import akka.actor.AbstractActor;
+import akka.actor.Props;
+import akka.event.Logging;
+import akka.event.LoggingAdapter;
+
+/**
+ * User Actor
+ *
+ */
+public class UserActor extends AbstractActor {
+
+ LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
+
+ /**
+ * In memory List to hold the users added via POST operation.
+ */
+ private final List users = new ArrayList<>();
+
+ /**
+ * To define UserActor Props.
+ *
+ * @return Props
+ */
+ static Props props() {
+ return Props.create(UserActor.class);
+ }
+
+ /**
+ * createReveive() implementation
+ */
+ @Override
+ public Receive createReceive() {
+ return receiveBuilder().match(UserRegistryMessages.GetUsers.class, getUsers -> getSender().tell(new Users(users), getSelf()))
+ .match(UserRegistryMessages.CreateUser.class, createUser -> {
+ users.add(createUser.getUser());
+ getSender().tell(new UserRegistryMessages.ActionPerformed(String.format("User %s created.", createUser.getUser()
+ .getName())), getSelf());
+ })
+ .match(UserRegistryMessages.GetUser.class, getUser -> {
+ getSender().tell(users.stream()
+ .filter(user -> user.getName()
+ .equals(getUser.getName()))
+ .findFirst(), getSelf());
+ })
+ .match(UserRegistryMessages.DeleteUser.class, deleteUser -> {
+ users.removeIf(user -> user.getName()
+ .equals(deleteUser.getName()));
+ getSender().tell(new UserRegistryMessages.ActionPerformed(String.format("User %s deleted.", deleteUser.getName())), getSelf());
+
+ })
+ .matchAny(o -> log.info("received unknown message"))
+ .build();
+ }
+
+}
diff --git a/akka-http/src/main/java/com/baeldung/akkahttp/UserRegistryMessages.java b/akka-http/src/main/java/com/baeldung/akkahttp/UserRegistryMessages.java
new file mode 100644
index 0000000000..831819849a
--- /dev/null
+++ b/akka-http/src/main/java/com/baeldung/akkahttp/UserRegistryMessages.java
@@ -0,0 +1,70 @@
+package com.baeldung.akkahttp;
+
+/**
+ * Defines all messages related to User Actor
+ *
+ */
+public interface UserRegistryMessages {
+
+ class GetUsers implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ }
+
+ class ActionPerformed implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String description;
+
+ public ActionPerformed(String description) {
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+ }
+
+ class CreateUser implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private final User user;
+
+ public CreateUser(User user) {
+ this.user = user;
+ }
+
+ public User getUser() {
+ return user;
+ }
+ }
+
+ class GetUser implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private final String name;
+
+ public GetUser(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ class DeleteUser implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private final String name;
+
+ public DeleteUser(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+}
diff --git a/akka-http/src/main/java/com/baeldung/akkahttp/UserRoutes.java b/akka-http/src/main/java/com/baeldung/akkahttp/UserRoutes.java
new file mode 100644
index 0000000000..aa3c9b612f
--- /dev/null
+++ b/akka-http/src/main/java/com/baeldung/akkahttp/UserRoutes.java
@@ -0,0 +1,98 @@
+package com.baeldung.akkahttp;
+
+import java.time.Duration;
+import java.util.Optional;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.TimeUnit;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.event.Logging;
+import akka.event.LoggingAdapter;
+import akka.http.javadsl.marshallers.jackson.Jackson;
+import akka.http.javadsl.model.StatusCodes;
+import akka.http.javadsl.server.AllDirectives;
+import akka.http.javadsl.server.PathMatchers;
+import akka.http.javadsl.server.Route;
+import akka.pattern.PatternsCS;
+import akka.util.Timeout;
+
+public class UserRoutes extends AllDirectives {
+
+ private final ActorRef userActorRef;
+ private final LoggingAdapter log;
+ Timeout timeout = new Timeout(Duration.create(5, TimeUnit.SECONDS));
+
+ public UserRoutes(ActorSystem system, ActorRef userActorRef) {
+ this.userActorRef = userActorRef;
+ log = Logging.getLogger(system, this);
+ }
+
+ public Route routes() {
+ return pathPrefix("users", () -> route(getOrPostUsers(), path(PathMatchers.segment(), name -> route(getUser(name), deleteUser(name)))));
+ }
+
+ /**
+ * Defines and returns a route to get the user by name
+ *
+ * @param name
+ * @return Route
+ */
+ private Route getUser(String name) {
+
+ Route getRoute = get(() -> {
+ CompletionStage> user = PatternsCS.ask(userActorRef, new UserRegistryMessages.GetUser(name), timeout)
+ .thenApply(obj -> (Optional) obj);
+
+ return onSuccess(() -> user, performed -> {
+ if (performed.isPresent())
+ return complete(StatusCodes.OK, performed.get(), Jackson.marshaller());
+ else
+ return complete(StatusCodes.NOT_FOUND);
+ });
+ });
+ return getRoute;
+ }
+
+ /**
+ * Defines and returns a Route to delete the user by name.
+ *
+ * @param name
+ * @return Route
+ */
+ private Route deleteUser(String name) {
+
+ Route deleteRoute = delete(() -> {
+ CompletionStage userDeleted = PatternsCS.ask(userActorRef, new UserRegistryMessages.DeleteUser(name), timeout)
+ .thenApply(obj -> (ActionPerformed) obj);
+
+ return onSuccess(() -> userDeleted, performed -> {
+ log.info("Deleted user [{}]: {}", name, performed.getDescription());
+ return complete(StatusCodes.OK, performed, Jackson.marshaller());
+ });
+ });
+
+ return deleteRoute;
+ }
+
+ /**
+ * Defines two routes, one to get all users and the other is to post users.
+ *
+ * @return
+ */
+ private Route getOrPostUsers() {
+ return pathEnd(() -> route(get(() -> {
+ CompletionStage futureUsers = PatternsCS.ask(userActorRef, new UserRegistryMessages.GetUsers(), timeout)
+ .thenApply(obj -> (Users) obj);
+ return onSuccess(() -> futureUsers, users -> complete(StatusCodes.OK, users, Jackson.marshaller()));
+ }), post(() -> entity(Jackson.unmarshaller(User.class), user -> {
+ CompletionStage userCreated = PatternsCS.ask(userActorRef, new CreateUser(user), timeout)
+ .thenApply(obj -> (ActionPerformed) obj);
+ return onSuccess(() -> userCreated, performed -> {
+ log.info("Created user [{}]: {}", user.getName(), performed.getDescription());
+ return complete(StatusCodes.CREATED, performed, Jackson.marshaller());
+ });
+ }))));
+ }
+
+}
diff --git a/akka-http/src/main/java/com/baeldung/akkahttp/Users.java b/akka-http/src/main/java/com/baeldung/akkahttp/Users.java
new file mode 100644
index 0000000000..e5e6c62c06
--- /dev/null
+++ b/akka-http/src/main/java/com/baeldung/akkahttp/Users.java
@@ -0,0 +1,25 @@
+package com.baeldung.akkahttp;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class is used to send the response enclosed by Users.
+ *
+ */
+public class Users {
+
+ private final List users;
+
+ public Users() {
+ this.users = new ArrayList<>();
+ }
+
+ public Users(List users) {
+ this.users = users;
+ }
+
+ public List getUsers() {
+ return users;
+ }
+}
diff --git a/pom.xml b/pom.xml
index 302530fd24..d0d0fa7049 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1254,6 +1254,7 @@
aws
aws-lambda
akka-streams
+ akka-http
algorithms
annotations
apache-cxf