This is an automated email from the ASF dual-hosted git repository.

fanningpj pushed a commit to branch wip-adding-tests
in repository 
https://gitbox.apache.org/repos/asf/incubator-pekko-http-quickstart-scala-g8.git

commit 2de7d16b7e168684c83afa65ca0abbb3f0e9719b
Author: henrikengstrom <[email protected]>
AuthorDate: Fri Jun 16 17:51:26 2017 -0400

    Revamping of seed template into a "Hello World" Akka Http tutorial. 
Completely new sample code and docs.
---
 build.sbt                                          |   6 ++
 docs/build.sbt                                     |  10 ++
 docs/src/main/paradox/backend.md                   |  10 ++
 docs/src/main/paradox/images/hello-akka-http.png   | Bin 0 -> 280372 bytes
 docs/src/main/paradox/images/idea-open-project.png | Bin 0 -> 127616 bytes
 .../main/paradox/images/idea-running-project.png   | Bin 0 -> 150403 bytes
 docs/src/main/paradox/index.md                     |  86 +++++++++++++++
 docs/src/main/paradox/intellij-idea.md             |  26 +++++
 docs/src/main/paradox/json.md                      |  18 ++++
 docs/src/main/paradox/running-the-application.md   |  86 +++++++++++++++
 docs/src/main/paradox/server-class.md              | 117 +++++++++++++++++++++
 project/build.properties                           |   2 +-
 project/paradox.sbt                                |   2 +
 src/main/g8/build.sbt                              |  14 ++-
 src/main/g8/project/build.properties               |   2 +-
 .../g8/src/main/scala/com/example/WebServer.scala  |  32 ------
 .../main/scala/com/example/WebServerHttpApp.scala  |  25 -----
 .../main/scala/com/example/routes/BaseRoutes.scala |  17 ---
 .../scala/com/example/routes/SimpleRoutes.scala    |  20 ----
 .../lightbend/akka/http/sample/JsonSupport.scala   |   9 ++
 .../akka/http/sample/QuickstartServer.scala        |  98 +++++++++++++++++
 .../akka/http/sample/UserRegistryActor.scala       |  32 ++++++
 .../scala/com/example/WebServerHttpAppSpec.scala   |  42 --------
 .../scala/com/example/routes/BaseRoutesSpec.scala  |  22 ----
 .../com/example/routes/SimpleRoutesSpec.scala      |  32 ------
 25 files changed, 508 insertions(+), 200 deletions(-)

diff --git a/build.sbt b/build.sbt
index d937000..098e2f1 100644
--- a/build.sbt
+++ b/build.sbt
@@ -10,3 +10,9 @@ lazy val root = (project in file(".")).
     scriptedLaunchOpts ++= List("-Xms1024m", "-Xmx1024m", 
"-XX:ReservedCodeCacheSize=128m", "-XX:MaxPermSize=256m", "-Xss2m", 
"-Dfile.encoding=UTF-8"),
     resolvers += Resolver.url("typesafe", 
url("http://repo.typesafe.com/typesafe/ivy-releases/";))(Resolver.ivyStylePatterns)
   )
+
+// Documentation for this project:
+//    sbt "project docs" "~ paradox"
+//    open docs/target/paradox/site/main/index.html
+lazy val docs = (project in file("docs"))
+  .enablePlugins(ParadoxPlugin)
diff --git a/docs/build.sbt b/docs/build.sbt
new file mode 100644
index 0000000..7222d72
--- /dev/null
+++ b/docs/build.sbt
@@ -0,0 +1,10 @@
+// Uses the out of the box generic theme.
+paradoxTheme := Some(builtinParadoxTheme("generic"))
+
+scalaVersion := "2.12.2"
+
+paradoxProperties in Compile ++= Map(
+  "snip.g8root.base_dir" -> "../../../../src/main/g8",
+  "snip.g8src.base_dir" -> "../../../../src/main/g8/src/main/",
+  "snip.g8srctest.base_dir" -> "../../../../src/main/g8/src/test/"
+)
diff --git a/docs/src/main/paradox/backend.md b/docs/src/main/paradox/backend.md
new file mode 100644
index 0000000..d14110e
--- /dev/null
+++ b/docs/src/main/paradox/backend.md
@@ -0,0 +1,10 @@
+Backend
+-------
+
+It is probably an exaggeration to call this for a "backend" since it, in this 
sample, only consists of a basic actor. In a real system, we would have many 
actors interacting with each other and perhaps a database or microservices. 
However, since the focus of this tutorial is on Akka Http, it is not very 
important what this backend does but more how to interact with a backend from 
within Akka Http. Hopefully, you already have a good grasp of how to 
communicate back and forth between Akka  [...]
+
+If you feel you should brush up your Akka Actor knowledge, then the [getting 
started guide]((http://developer.lightbend.com/guides/akka-quickstart-scala/)) 
for Akka actors tutorial is a good start.
+
+The sample code in the `UserRegistryActor` is very simple. It keeps registered 
users in a `Set`. Once it receives messages it will match those into what 
action it should take:
+
+@@snip 
[UserRegistryActor.scala]($g8src$/scala/com/lightbend/akka/http/sample/UserRegistryActor.scala)
diff --git a/docs/src/main/paradox/images/hello-akka-http.png 
b/docs/src/main/paradox/images/hello-akka-http.png
new file mode 100644
index 0000000..10ba689
Binary files /dev/null and b/docs/src/main/paradox/images/hello-akka-http.png 
differ
diff --git a/docs/src/main/paradox/images/idea-open-project.png 
b/docs/src/main/paradox/images/idea-open-project.png
new file mode 100644
index 0000000..9c051a4
Binary files /dev/null and b/docs/src/main/paradox/images/idea-open-project.png 
differ
diff --git a/docs/src/main/paradox/images/idea-running-project.png 
b/docs/src/main/paradox/images/idea-running-project.png
new file mode 100644
index 0000000..12e0310
Binary files /dev/null and 
b/docs/src/main/paradox/images/idea-running-project.png differ
diff --git a/docs/src/main/paradox/index.md b/docs/src/main/paradox/index.md
new file mode 100644
index 0000000..8b8cab6
--- /dev/null
+++ b/docs/src/main/paradox/index.md
@@ -0,0 +1,86 @@
+Akka Http Quickstart with Scala
+===============================
+
+The Akka HTTP modules implement a full server- and client-side HTTP stack on 
top of akka-actor and akka-stream.  It’s not a web-framework but rather a more 
general toolkit for providing and consuming HTTP-based services.  While 
interaction with a browser is of course also in scope, it is not the primary 
focus of Akka HTTP.
+
+Akka HTTP follows a rather open design and many times offers several different 
API levels for "doing the same thing."  The users get to pick the API level of 
abstraction that is most suitable for their applications.  This approach means 
that, if you have trouble achieving something using a high-level API, there’s a 
good chance that you can get it done with a low-level API, which offers more 
flexibility but might require you to write more application code.
+
+This Hello World example demonstrates some Akka HTTP fundamentals. Within 30 
minutes, you should be able to download, run the sample application, and use 
this documentation to guide you through this example's building blocks.
+
+## Prerequisite
+
+Having a basic understanding of Akka actors will help the reader of this 
guide. There is a [getting started 
guide]((http://developer.lightbend.com/guides/akka-quickstart-scala/)) for Akka 
actors in if you feel like brushing up your knowledge thereof.
+
+## Downloading the example
+
+The Hello World example for Scala is a zipped project that includes a 
distribution of sbt (build tool). You can run it on Linux, MacOS, or Windows. 
The only prerequisite is Java 8.
+
+Download and unzip the example:
+
+1. Download the zip file from Lightbend Tech Hub by clicking `CREATE A PROJECT 
FOR ME`.
+2. Extract the zip file to a convenient location:
+
+* On Linux and OSX systems, open a terminal and use the command unzip 
akka-quickstart-scala.zip. Note: On OSX, if you unzip using Archiver, you also 
have to make the sbt files executable:
+
+```
+$ chmod u+x ./sbt
+$ chmod u+x ./sbt-dist/bin/sbt
+```
+
+* On Windows, use a tool such as File Explorer to extract the project.
+
+## Running the example
+
+To run Hello World:
+
+In a console, change directories to the top level of the unzipped project.
+
+For example, if you used the default project name, 
`akka-http-quickstart-scala`, and extracted the project to your root directory, 
from the root directory, enter: cd akka-http-quickstart-scala
+
+Enter `./sbt` on OSX/Linux or run `sbt.bat` on Windows to start 
[sbt](http://www.scala-sbt.org).
+
+sbt downloads project dependencies. The `>` prompt indicates sbt has started 
in interactive mode.
+
+At the sbt prompt, enter `run`.
+
+sbt builds the project and runs Hello World.
+
+The output should look something like this:
+
+```
+[info] Loading global plugins from /Users/x/.sbt/0.13/plugins
+...
+[info] Running com.lightbend.akka.http.sample.QuickstartServer
+Server online at http://localhost:8080/
+Press RETURN to stop...
+```
+
+The command above will start an Akka Http server. We will look at how to 
invoke the available endpoints of the server later in this guide.
+
+Congratulations, you just ran your first Akka Http app. Now take a look at 
what happened under the covers.
+
+## What Hello World does
+
+When Hello World starts up it creates an ActorSystem and registers so-called 
routes that are available in this ActorSystem. The routes are bound to a port, 
in this case, `localhost:8080`. Below is an overview of what things look like 
when the application starts:
+
+![Architecture](images/hello-akka-http.png)
+
+In this sample application, we are implementing a [REST 
service](https://en.wikipedia.org/wiki/Representational_state_transfer). The 
idea is to build a simple user registry service.
+
+The endpoints available are `/users` and `/user` with some attached HTTP 
directives and parameters/payloads. When invoked, endpoints will interact with 
an actor, "userRegistryActor", which represents the business logic of this 
sample application.
+
+In the following sections, we will take a detailed look at the individual 
pieces of this application.
+
+## The Akka HTTP philosophy
+
+Akka HTTP is designed specifically as "not-a-framework," not because we don’t 
like frameworks, but for use cases where a framework is not the right choice.  
Akka HTTP is for building integration layers based on HTTP and as such tries to 
"stay on the sidelines."  Therefore, a typical application doesn't sit on top 
of Akka HTTP but instead on top of whatever makes sense and uses Akka HTTP 
merely for the HTTP integration needs.
+
+@@@index
+
+* [The server](server-class.md)
+* [The backend](backend.md)
+* [JSON](json.md)
+* [Running the application](running-the-application.md)
+* [IntelliJ IDEA](intellij-idea.md)
+
+@@@
diff --git a/docs/src/main/paradox/intellij-idea.md 
b/docs/src/main/paradox/intellij-idea.md
new file mode 100644
index 0000000..7aaeb71
--- /dev/null
+++ b/docs/src/main/paradox/intellij-idea.md
@@ -0,0 +1,26 @@
+IntelliJ IDEA
+-------------
+
+[IntelliJ](https://www.jetbrains.com/idea/) from JetBrains is one of the 
leading IDEs in the Java/Scala community, and it has excellent support for Akka 
Http. This section will guide you through setting up, testing and running the 
sample project.
+
+## Setting up the project
+
+Open IntelliJ and select File -> Open... and point to the directory where you 
have installed the sample project. There should be a pop-up like this:
+
+![Open Project](images/idea-open-project.png)
+
+Fill out the settings according to the above and press `OK` to import the 
project. If IntelliJ will warn about missing Scala SDK, it is only to follow 
the instructions to add support.
+
+## Inspecting the code
+
+If we open up the file 
`src/main/scala/com/lightbend/akka/http/sample/QuickstartServer.scala` we can 
see a lot of lines beginning with //# .... These lines are used as directives 
for this documentation. To get rid of these lines from the source code we can 
utilize the awesome Find/Replace functionality in IntelliJ. Select Edit -> Find 
-> Replace in Path.... Check the Regex box and add the following regex [//#].* 
and click on Replace in Find Window.... Select to replace all occurrences an 
[...]
+
+## Running the application
+
+Right click on the file 
`src/main/scala/com/lightbend/akka/http/sample/QuickstartServer.scala` and 
select Run 'QuickstartServer' and the output should look like this:
+
+![Running Project](images/idea-running-project.png)
+
+## Tutorial done!
+
+Congratulations! We have now learned enough concepts to get started with 
building real-world Akka Http applications. Of course, there is plenty of more 
that we can do with Akka Http and the 
[documentation](http://doc.akka.io/docs/akka-http/current/scala/http/index.html)
 is a good starting point if there is something more you need.
diff --git a/docs/src/main/paradox/json.md b/docs/src/main/paradox/json.md
new file mode 100644
index 0000000..bf91eab
--- /dev/null
+++ b/docs/src/main/paradox/json.md
@@ -0,0 +1,18 @@
+JSON
+----
+
+In the server class, we saw that JSON is somehow converted into Scala classes 
and vice versa. In this section, we shall look at how this is implemented and 
what you need to do to make it work.
+
+Let's take a look at the server class definition once again:
+
+@@snip 
[QuickstartServer.scala]($g8src$/scala/com/lightbend/akka/http/sample/QuickstartServer.scala)
 { #main-class }
+
+See the `JsonSupport` up there? This is a trait that we have created and it 
looks like this:
+
+@@snip 
[JsonSupport.scala]($g8src$/scala/com/lightbend/akka/http/sample/JsonSupport.scala)
+
+The above trait defines two implicit values; `userJsonFormat` and 
`usersJsonFormat`. To do so we use the `jsonFormatX` methods, from [Spray 
Json](),  where X is representing the number of parameters in the underlying 
case classes:
+
+@@snip 
[UserRegistryActor.scala]($g8src$/scala/com/lightbend/akka/http/sample/UserRegistryActor.scala)
 { #user-case-classes }
+
+By defining the Formatters as `implicit`, we ensure that the compiler can map 
the formatting functionality with the case classes we want to convert. We won't 
go into the underlying functionality for how the formatters are implemented. 
All we have to remember for now is to define the formatters as implicit and 
that the Formatter used should map the number of parameters of "its" case class.
diff --git a/docs/src/main/paradox/running-the-application.md 
b/docs/src/main/paradox/running-the-application.md
new file mode 100644
index 0000000..6dafe7c
--- /dev/null
+++ b/docs/src/main/paradox/running-the-application.md
@@ -0,0 +1,86 @@
+Running the application
+-----------------------
+
+You can run the Hello World application from the command line or an IDE. The 
final topic in this guide describes how to run it from IntelliJ IDEA. However, 
before we get there, let’s take a quick look at the build tool: sbt.
+
+## The build files
+
+sbt uses a build.sbt file to handle the project. This project’s build.sbt file 
looks like this:
+
+@@snip [build.sbt]($g8root$/build.sbt)
+
+## Running the project
+
+We run the application from a console/terminal window:
+
+1. Enter `./sbt` on OSX/Linux or `sbt.bat` on Windows
+
+sbt downloads project dependencies. The `>` prompt indicates sbt has started 
in interactive mode.
+
+2. At the sbt prompt, enter `run`.
+
+The output should look like this:
+
+```
+...
+[info] Running com.lightbend.akka.http.sample.QuickstartServer
+Server online at http://localhost:8080/
+Press RETURN to stop...
+```
+
+## Testing the application
+
+The Akka Http server is now running, and we will use the 
[cURL](https://en.wikipedia.org/wiki/CURL) command to test the application. If 
you should prefer to use your browser to test the service than a tool like 
[RESTClient](http://restclient.net/) may be good to install.
+
+Open another console/terminal window to investigate the functionality of the 
application.
+
+We start by looking at the existing users (there should be none as we just 
launched the application):
+
+```
+$ curl http://localhost:8080/users
+{"users":[]}
+```
+
+The next step is to add a couple of users:
+```
+$ curl -H "Content-type: application/json" -X POST -d '{"name": "MrX", "age": 
31, "countryOfResidence": "Canada"}' http://localhost:8080/user
+User MrX created.
+
+$ curl -H "Content-type: application/json" -X POST -d '{"name": "Anonymous", 
"age": 55, "countryOfResidence": "Iceland"}' http://localhost:8080/user
+User Anonymous created.
+
+$ curl -H "Content-type: application/json" -X POST -d '{"name": "Bill", "age": 
67, "countryOfResidence": "USA"}' http://localhost:8080/user
+User Bill created.
+```
+
+We can try to retrieve user information for some various users now:
+
+```
+$ curl http://localhost:8080/user/MrX
+{"name":"MrX","age":31,"countryOfResidence":"Canada"}
+
+$ curl http://localhost:8080/user/SomeUnknownUser
+User SomeUnknownUser is not registered.
+```
+
+Now, when we inquire the system for all existing users it looks like this:
+
+```
+$ curl http://localhost:8080/users
+{"users":[{"name":"Anonymous","age":55,"countryOfResidence":"Iceland"},{"name":"MrX","age":31,"countryOfResidence":"Canada"},{"name":"Bill","age":67,"countryOfResidence":"USA"}]}
+```
+
+Next, we should make sure that the delete functionality works as expected:
+
+```
+$ curl -X DELETE http://localhost:8080/user/Bill
+User Bill deleted.
+
+$ curl http://localhost:8080/user/Bill
+User Bill is not registered.
+
+$ curl http://localhost:8080/users
+{"users":[{"name":"Anonymous","age":55,"countryOfResidence":"Iceland"},{"name":"MrX","age":31,"countryOfResidence":"Canada"}]}
+```
+
+We have now tried all the functionality available in this sample. The next 
step is to see how we can use an IDE to work with the application.
diff --git a/docs/src/main/paradox/server-class.md 
b/docs/src/main/paradox/server-class.md
new file mode 100644
index 0000000..45e4782
--- /dev/null
+++ b/docs/src/main/paradox/server-class.md
@@ -0,0 +1,117 @@
+The main class
+----------------
+
+Let's dissect the main class, `QuickstartServer`. We make this class runnable 
by extending `App` (we will discuss the trait `JsonSupport` later):
+
+@@snip 
[QuickstartServer.scala]($g8src$/scala/com/lightbend/akka/http/sample/QuickstartServer.scala)
 { #main-class }
+
+Now that we have a class to run we should add some Akka Http fundamentals with 
which we will build our RESTful web service:
+
+* define routes bound to endpoints and HTTP directives
+* create a server bound to an IP and port that will handle all requests
+* add error handling for when something goes wrong
+
+Let us take a look at each of these steps here below.
+
+## Routes
+
+For our service we want to define the following endpoints:
+
+| Path        | Http directive  | Intent             | Returns              |
+|-------------|-----------------|--------------------|----------------------|
+| /user       | POST            | Create a new user  | Confirmation message |
+| /user/$ID   | GET             | Retrieve a user    | JSON payload         |
+| /user/$ID   | DELETE          | Remove a user      | Confirmation message |
+| /users      | GET             | Retrieve all users | JSON payload         |
+
+Akka Http provides a [domain-specific 
language](https://en.wikipedia.org/wiki/Domain-specific_language) (DSL) to 
simplify the routes/endpoints definition. Each route is composed of one or more 
`akka.http.scaladsl.server.Directives`, e.g. `path`, `get`, `post`, `complete`, 
etc.
+
+### Creating a new user
+
+Let us take a look at the source code for the first endpoint, the `/user` URI 
with a `POST` directive, used to create a new user:
+
+@@snip 
[QuickstartServer.scala]($g8src$/scala/com/lightbend/akka/http/sample/QuickstartServer.scala)
 { #user-post }
+
+The snippet above contains a couple of interesting building blocks:
+
+* `path` : matches against the incoming URI, in this case, we want to get all 
requests that matches `user`.
+* `post` : matches against the incoming Http directive, in this case, we are 
matching against `POST`.
+* `entity(as[User])` : automatically converts the incoming payload, in this 
case, we expect JSON, into an entity. We will look more at this functionality 
in the @ref:[JSON](json.md) section.
+* `complete` : used to reply back to the request. The `StatusCodes.Created` is 
translated to Http response code 201. We also send back information to the 
caller in the form of a string.    
+
+When this `Route` is called, we want to create a new user, and we do so by 
sending a message to the actor `userRegistryActor`. We will look at the 
implementation of this actor later.
+
+### Retrieving and removing a user
+
+Next we need to define how to retrieve and remove a user, i.e. for the case 
when the URI `/user/$ID` is used where `$ID` is the id of the user:
+
+@@snip 
[QuickstartServer.scala]($g8src$/scala/com/lightbend/akka/http/sample/QuickstartServer.scala)
 { #user-get-delete }
+
+This Route snippet contains a couple of interesting concepts:
+
+* `path("user" / Segment) { => user` : this bit of code matches against URIs 
of the exact format `/user/$ID` and the `Segment` is automatically extracted 
into the `user` variable so that we can get to the value passed in the URI. For 
example `/user/Bruce` will populate the `user` variable with the value "Bruce."
+* `get` : matches against the incoming Http directive.
+
+Let's break down the "business logic" in the first Route:
+
+@@snip 
[QuickstartServer.scala]($g8src$/scala/com/lightbend/akka/http/sample/QuickstartServer.scala)
 { #retrieve-user-info }
+
+The code above uses the so-called 
[ask](http://doc.akka.io/docs/akka/current/scala/actors.html#send-messages) in 
Akka. This will send a message asynchronously and return a `Future` 
representing a _possible_ reply. The code above maps the reply to the type 
`UserInfo`. When the future completes, it will use the second part of the code 
to evaluate to either `Success`, with or without a result, or a `Failure`. 
Regardless of the outcome of the future, we should return something to the 
request [...]
+
+The remaining directives used for this route are:
+
+* `~` : fuses `Route`s together - this will become more apparent when you see 
the complete `Route` definition here below.
+* `delete` : matches against the Http directive `DELETE`.
+
+The "business logic" for when deleting a user is straight forward; send an 
instruction about removing a user to the user registry actor and return a 
status code to the client (which in this case is `StatusCodes.OK`, i.e. Http 
200)
+
+### Retrieving all users
+
+Finally we should implement functionality to retrieve all registered users:
+
+@@snip 
[QuickstartServer.scala]($g8src$/scala/com/lightbend/akka/http/sample/QuickstartServer.scala)
 { #users-get }
+
+This code is based on the same structure as the code above, send a message to 
the user registry actor using an `ask` and pass on the `Future` to the 
`complete` method.
+
+Why do we not use an `onComplete` as we did for when retrieving a particular 
user? The difference is that when we use `GetUsers` there will always be 
something returned; an empty list means that there are no registered users. 
However, when we asked for a particular user ID, there might be the case that 
there is no such user recorded and we need a way to tell this to the client. 
When sent a `GetUser(name)` the user registry actor therefore send back an 
`Option[UserInfo]`. It could be that [...]
+
+### The complete Route
+
+Below is the complete `Route` definition used in the sample application:
+
+@@snip 
[QuickstartServer.scala]($g8src$/scala/com/lightbend/akka/http/sample/QuickstartServer.scala)
 { #all-routes }
+
+So far we have referred to `Route` without explaining what it is but now is 
the time to do so. Under the hood, Akka Http uses [Akka 
Streams](http://doc.akka.io/docs/akka/current/scala/stream/index.html). We 
don't have time to cover Akka Streams here, but if you are interested, you 
should take a look at the Hello World sample application for Streams. Since 
Akka Http is built on top of Akka Streams, it means that some concepts of 
Streams are available for us to use. In the case of `Route`  [...]
+
+## Http server
+
+To set up an Akka Http server we must first define some implicit values that 
will be used by the server:
+
+@@snip 
[QuickstartServer.scala]($g8src$/scala/com/lightbend/akka/http/sample/QuickstartServer.scala)
 { #server-bootstrapping }
+
+What does the above mean and why do we need it?
+
+* `ActorSystem` : the context in which actors will run. What actors, you may 
wonder? Akka Streams uses actors under the hood, and the actor system defined 
in this `val` will be picked up and used by Streams.
+* `ActorMaterializer` : also Akka Streams related - it uses the materializer 
to allocate all the necessary resources it needs to run.
+
+With that defined we can move on to instantiate the server:
+
+@@snip 
[QuickstartServer.scala]($g8src$/scala/com/lightbend/akka/http/sample/QuickstartServer.scala)
 { #http-server }
+
+We provide three parameters; `routes`, the hostname, and the port. That's it! 
When running this program, we will have an Akka Http server on our machine 
(localhost) on port 8080. Note that starting a server happens asynchronously 
and therefore a `Future` is returned by the `bindAndHandle` method.
+
+We should also add code for stopping the server. To do so we use the 
`StdIn.readLine()` method that will wait until RETURN is pressed on the 
keyboard. When that happens we `flatMap` the `Future` returned when we started 
the server to get to the `unbind()` method. Unbinding is also an asynchronous 
function and when the `Future` returned by `unbind()` is completes we make sure 
that the actor system is properly terminated.
+
+## Error handling
+
+Finally, we should take a look at how to handle errors. We know, as the astute 
engineers we are, that errors will happen. We should prepare our program for 
this and error handling should not be an afterthought when we build systems.
+
+In this sample, we use a very simple exception handler which catches all 
unexpected exceptions and responds back to the client with an 
`InternalServerError` (HTTP 500) with an error message and for what URI the 
exception happened. We extract the URI by using the `extractUri` directive.
+
+@@snip 
[QuickstartServer.scala]($g8src$/scala/com/lightbend/akka/http/sample/QuickstartServer.scala)
 { #exception-handler }
+
+## The complete server code
+
+Here is the complete server code used in the sample:
+
+@@snip 
[QuickstartServer.scala]($g8src$/scala/com/lightbend/akka/http/sample/QuickstartServer.scala)
diff --git a/project/build.properties b/project/build.properties
index 27e88aa..64317fd 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=0.13.13
+sbt.version=0.13.15
diff --git a/project/paradox.sbt b/project/paradox.sbt
new file mode 100644
index 0000000..01bcc5c
--- /dev/null
+++ b/project/paradox.sbt
@@ -0,0 +1,2 @@
+// sbt-paradox, used for documentation
+addSbtPlugin("com.lightbend.paradox" % "sbt-paradox" % "0.2.11")
diff --git a/src/main/g8/build.sbt b/src/main/g8/build.sbt
index f8ade85..030ddd5 100644
--- a/src/main/g8/build.sbt
+++ b/src/main/g8/build.sbt
@@ -1,18 +1,16 @@
-lazy val akkaHttpVersion = "$akka_http_version$"
-lazy val akkaVersion    = "$akka_version$"
+lazy val akkaHttpVersion = "10.0.9"
+lazy val akkaVersion    = "2.5.2"
 
 lazy val root = (project in file(".")).
   settings(
     inThisBuild(List(
       organization    := "com.example",
-      scalaVersion    := "$scala_version$"
+      scalaVersion    := "2.12.2"
     )),
     name := "$name$",
     libraryDependencies ++= Seq(
-      "com.typesafe.akka" %% "akka-http"         % akkaHttpVersion,
-      "com.typesafe.akka" %% "akka-http-xml"     % akkaHttpVersion,
-      "com.typesafe.akka" %% "akka-stream"       % akkaVersion,
-      "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion % Test,
-      "org.scalatest"     %% "scalatest"         % "3.0.1"         % Test
+      "com.typesafe.akka" %% "akka-http"            % akkaHttpVersion,
+      "com.typesafe.akka" %% "akka-http-spray-json" % akkaHttpVersion,
+      "com.typesafe.akka" %% "akka-stream"          % akkaVersion
     )
   )
diff --git a/src/main/g8/project/build.properties 
b/src/main/g8/project/build.properties
index 27e88aa..64317fd 100644
--- a/src/main/g8/project/build.properties
+++ b/src/main/g8/project/build.properties
@@ -1 +1 @@
-sbt.version=0.13.13
+sbt.version=0.13.15
diff --git a/src/main/g8/src/main/scala/com/example/WebServer.scala 
b/src/main/g8/src/main/scala/com/example/WebServer.scala
deleted file mode 100644
index 2baafa7..0000000
--- a/src/main/g8/src/main/scala/com/example/WebServer.scala
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.example
-
-import akka.actor.ActorSystem
-import akka.http.scaladsl.Http
-import akka.http.scaladsl.server.Directives
-import akka.stream.ActorMaterializer
-import com.example.routes.{ BaseRoutes, SimpleRoutes }
-
-import scala.io.StdIn
-
-object WebServer extends Directives with SimpleRoutes {
-  def main(args: Array[String]) {
-
-    implicit val system = ActorSystem("my-system")
-    implicit val materializer = ActorMaterializer()
-    // needed for the future flatMap/onComplete in the end
-    implicit val executionContext = system.dispatcher
-
-    val bindingFuture = Http().bindAndHandle(routes, "localhost", 8080)
-
-    println(s"Server online at http://localhost:8080/\nPress RETURN to 
stop...")
-    StdIn.readLine() // let it run until user presses return
-    bindingFuture
-      .flatMap(_.unbind()) // trigger unbinding from the port
-      .onComplete(_ => system.terminate()) // and shutdown when done
-  }
-
-  // Here you can define all the different routes you want to have served by 
this web server
-  // Note that routes might be defined in separated traits like the current 
case
-  val routes = BaseRoutes.baseRoutes ~ simpleRoutes
-
-}
diff --git a/src/main/g8/src/main/scala/com/example/WebServerHttpApp.scala 
b/src/main/g8/src/main/scala/com/example/WebServerHttpApp.scala
deleted file mode 100644
index e41be52..0000000
--- a/src/main/g8/src/main/scala/com/example/WebServerHttpApp.scala
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.example
-
-import 
akka.http.scaladsl.marshallers.xml.ScalaXmlSupport.defaultNodeSeqMarshaller
-import akka.http.scaladsl.server.{ HttpApp, Route }
-
-/**
- * Server will be started calling `WebServerHttpApp.startServer("localhost", 
8080)`
- * and it will be shutdown after pressing return.
- */
-object WebServerHttpApp extends HttpApp with App {
-  // Routes that this WebServer must handle are defined here
-  // Please note this method was named `route` in versions prior to 10.0.7
-  def routes: Route =
-    pathEndOrSingleSlash { // Listens to the top `/`
-      complete("Server up and running") // Completes with some text
-    } ~
-      path("hello") { // Listens to paths that are exactly `/hello`
-        get { // Listens only to GET requests
-          complete(<html><body><h1>Say hello to akka-http</h1></body></html>) 
// Completes with some text
-        }
-      }
-
-  // This will start the server until the return key is pressed
-  startServer("localhost", 8080)
-}
diff --git a/src/main/g8/src/main/scala/com/example/routes/BaseRoutes.scala 
b/src/main/g8/src/main/scala/com/example/routes/BaseRoutes.scala
deleted file mode 100644
index bd1ce87..0000000
--- a/src/main/g8/src/main/scala/com/example/routes/BaseRoutes.scala
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.example.routes
-
-import akka.http.scaladsl.server.Route
-import akka.http.scaladsl.server.directives.PathDirectives.pathEndOrSingleSlash
-import akka.http.scaladsl.server.directives.RouteDirectives.complete
-
-/**
- * Routes can be defined in separated classes like shown in here
- */
-object BaseRoutes {
-
-  // This route is the one that listens to the top level '/'
-  lazy val baseRoutes: Route =
-    pathEndOrSingleSlash { // Listens to the top `/`
-      complete("Server up and running") // Completes with some text
-    }
-}
diff --git a/src/main/g8/src/main/scala/com/example/routes/SimpleRoutes.scala 
b/src/main/g8/src/main/scala/com/example/routes/SimpleRoutes.scala
deleted file mode 100644
index 177981b..0000000
--- a/src/main/g8/src/main/scala/com/example/routes/SimpleRoutes.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.example.routes
-
-import 
akka.http.scaladsl.marshallers.xml.ScalaXmlSupport.defaultNodeSeqMarshaller
-import akka.http.scaladsl.server.directives.MethodDirectives.get
-import akka.http.scaladsl.server.directives.PathDirectives.path
-import akka.http.scaladsl.server.directives.RouteDirectives.complete
-
-/**
- * Routes can be defined in separated classes like shown in here
- */
-trait SimpleRoutes {
-
-  // This `val` holds one route (of possibly many more that will be part of 
your Web App)
-  lazy val simpleRoutes =
-    path("hello") { // Listens to paths that are exactly `/hello`
-      get { // Listens only to GET requests
-        complete(<html><body><h1>Say hello to akka-http</h1></body></html>) // 
Completes with some html page
-      }
-    }
-}
diff --git 
a/src/main/g8/src/main/scala/com/lightbend/akka/http/sample/JsonSupport.scala 
b/src/main/g8/src/main/scala/com/lightbend/akka/http/sample/JsonSupport.scala
new file mode 100644
index 0000000..6f19b73
--- /dev/null
+++ 
b/src/main/g8/src/main/scala/com/lightbend/akka/http/sample/JsonSupport.scala
@@ -0,0 +1,9 @@
+package com.lightbend.akka.http.sample
+
+import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
+import spray.json.DefaultJsonProtocol
+
+trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
+  implicit val userJsonFormat = jsonFormat3(User)
+  implicit val usersJsonFormat = jsonFormat1(Users)
+}
diff --git 
a/src/main/g8/src/main/scala/com/lightbend/akka/http/sample/QuickstartServer.scala
 
b/src/main/g8/src/main/scala/com/lightbend/akka/http/sample/QuickstartServer.scala
new file mode 100644
index 0000000..1279967
--- /dev/null
+++ 
b/src/main/g8/src/main/scala/com/lightbend/akka/http/sample/QuickstartServer.scala
@@ -0,0 +1,98 @@
+package com.lightbend.akka.http.sample
+
+import akka.actor.{ ActorRef, ActorSystem }
+import akka.pattern.ask
+import akka.util.Timeout
+
+import scala.concurrent.duration._
+import akka.stream.ActorMaterializer
+import akka.http.scaladsl.Http
+import akka.http.scaladsl.server.Directives._
+import akka.http.scaladsl.Http.ServerBinding
+import akka.http.scaladsl.model.StatusCodes
+import akka.http.scaladsl.server.{ ExceptionHandler, Route }
+import akka.http.scaladsl.server.directives.MethodDirectives.delete
+import akka.http.scaladsl.server.directives.MethodDirectives.get
+import akka.http.scaladsl.server.directives.MethodDirectives.post
+import akka.http.scaladsl.server.directives.RouteDirectives.complete
+import akka.http.scaladsl.server.directives.PathDirectives.path
+
+import scala.concurrent.ExecutionContext
+import scala.concurrent.Future
+import scala.io.StdIn
+import scala.util.{ Failure, Success }
+import com.lightbend.akka.http.sample.UserRegistryActor._
+
+//#main-class
+object QuickstartServer extends App with JsonSupport {
+  //#main-class
+  //#server-bootstrapping
+  implicit val system: ActorSystem = ActorSystem("helloAkkaHttpServer")
+  implicit val materializer: ActorMaterializer = ActorMaterializer()
+  //#server-bootstrapping
+
+  // Needed for the Future and its methods flatMap/onComplete in the end
+  implicit val executionContext: ExecutionContext = system.dispatcher
+
+  val userRegistryActor: ActorRef = system.actorOf(UserRegistryActor.props, 
"userRegistryActor")
+  implicit val timeout = Timeout(5 seconds)
+
+  //#exception-handler
+  implicit val exceptionHandler = ExceptionHandler {
+    case e: Exception =>
+      extractUri { uri =>
+        complete((StatusCodes.InternalServerError, s"Exception ${e.getMessage} 
happened for URI: $uri."))
+      }
+  }
+  //#exception-handler
+
+  //#all-routes
+  lazy val routes: Route =
+    //#user-post
+    path("user") {
+      post {
+        entity(as[User]) { user =>
+          userRegistryActor ! CreateUser(user)
+          complete((StatusCodes.Created, s"User ${user.name} created."))
+        }
+      }
+    } ~ //#user-post
+      //#user-get-delete
+      path("user" / Segment) { name =>
+        get {
+          //#retrieve-user-info
+          val userInfo: Future[UserInfo] = (userRegistryActor ? 
GetUser(name)).mapTo[UserInfo]
+          onComplete(userInfo) { r =>
+            r match {
+              case Success(UserInfo(Some(user))) => complete(user)
+              case Success(UserInfo(None)) => complete((StatusCodes.OK, s"User 
$name is not registered."))
+              case Failure(ex) => complete((StatusCodes.InternalServerError, 
ex))
+            }
+          }
+          //#retrieve-user-info
+        } ~
+          delete {
+            userRegistryActor ! DeleteUser(name)
+            complete((StatusCodes.OK, s"User $name deleted."))
+          }
+      } ~ //#user-get-delete
+      //#users-get
+      path("users") {
+        get {
+          val users: Future[Users] = (userRegistryActor ? 
GetUsers).mapTo[Users]
+          complete(users)
+        }
+      } //#users-get
+  //#all-routes
+
+  //#http-server
+  val serverBindingFuture: Future[ServerBinding] = 
Http().bindAndHandle(routes, "localhost", 8080)
+  println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
+  StdIn.readLine()
+  serverBindingFuture
+    .flatMap(_.unbind())
+    .onComplete(_ => system.terminate())
+  //#http-server
+  //#main-class
+}
+//#main-class
diff --git 
a/src/main/g8/src/main/scala/com/lightbend/akka/http/sample/UserRegistryActor.scala
 
b/src/main/g8/src/main/scala/com/lightbend/akka/http/sample/UserRegistryActor.scala
new file mode 100644
index 0000000..718f63e
--- /dev/null
+++ 
b/src/main/g8/src/main/scala/com/lightbend/akka/http/sample/UserRegistryActor.scala
@@ -0,0 +1,32 @@
+package com.lightbend.akka.http.sample
+
+import akka.actor.{ Actor, ActorLogging, Props }
+import scala.collection.mutable.Set
+
+case class UserInfo(maybeUser: Option[User])
+//#user-case-classes
+case class User(name: String, age: Int, countryOfResidence: String)
+case class Users(users: Seq[User])
+//#user-case-classes
+
+object UserRegistryActor {
+  final case object GetUsers
+  final case class CreateUser(user: User)
+  final case class GetUser(name: String)
+  final case class DeleteUser(name: String)
+
+  def props: Props = Props[UserRegistryActor]
+}
+
+class UserRegistryActor extends Actor with ActorLogging {
+  import UserRegistryActor._
+
+  val users: Set[User] = Set.empty[User]
+
+  def receive = {
+    case GetUsers => sender ! Users(users.toSeq)
+    case CreateUser(user) => users += user
+    case GetUser(name) => sender ! UserInfo(users.find(_.name == name))
+    case DeleteUser(name) => users.find(_.name == name) map { user => users -= 
user }
+  }
+}
diff --git a/src/main/g8/src/test/scala/com/example/WebServerHttpAppSpec.scala 
b/src/main/g8/src/test/scala/com/example/WebServerHttpAppSpec.scala
deleted file mode 100644
index 349ed19..0000000
--- a/src/main/g8/src/test/scala/com/example/WebServerHttpAppSpec.scala
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.example
-
-import 
akka.http.scaladsl.marshallers.xml.ScalaXmlSupport.defaultNodeSeqUnmarshaller
-import akka.http.scaladsl.model.StatusCodes
-import akka.http.scaladsl.server.Route
-import akka.http.scaladsl.testkit.ScalatestRouteTest
-import org.scalatest.{ Matchers, WordSpec }
-
-import scala.xml.NodeSeq
-
-class WebServerHttpAppSpec extends WordSpec with Matchers with 
ScalatestRouteTest {
-
-  "WebServiceHttpApp" should {
-    "answer to any request to `/`" in {
-      Get("/") ~> WebServerHttpApp.routes ~> check {
-        status shouldBe StatusCodes.OK
-        responseAs[String] shouldBe "Server up and running"
-      }
-      Post("/") ~> WebServerHttpApp.routes ~> check {
-        status shouldBe StatusCodes.OK
-        responseAs[String] shouldBe "Server up and running"
-      }
-    }
-    "answer to GET requests to `/hello`" in {
-      Get("/hello") ~> WebServerHttpApp.routes ~> check {
-        status shouldBe StatusCodes.OK
-        responseAs[NodeSeq] shouldBe <html><body><h1>Say hello to 
akka-http</h1></body></html>
-      }
-    }
-    "not handle a POST request to `/hello`" in {
-      Post("/hello") ~> WebServerHttpApp.routes ~> check {
-        handled shouldBe false
-      }
-    }
-    "respond with 405 when not issuing a GET to `/hello` and route is sealed" 
in {
-      Put("/hello") ~> Route.seal(WebServerHttpApp.routes) ~> check {
-        status shouldBe StatusCodes.MethodNotAllowed
-      }
-    }
-  }
-
-}
diff --git a/src/main/g8/src/test/scala/com/example/routes/BaseRoutesSpec.scala 
b/src/main/g8/src/test/scala/com/example/routes/BaseRoutesSpec.scala
deleted file mode 100644
index fa7d616..0000000
--- a/src/main/g8/src/test/scala/com/example/routes/BaseRoutesSpec.scala
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.example.routes
-
-import akka.http.scaladsl.model.StatusCodes
-import akka.http.scaladsl.testkit.ScalatestRouteTest
-import org.scalatest.{ Matchers, WordSpec }
-
-class BaseRoutesSpec extends WordSpec with Matchers with ScalatestRouteTest {
-
-  "BaseRoute" should {
-    "answer to any request to `/`" in {
-      Get("/") ~> BaseRoutes.baseRoutes ~> check {
-        status shouldBe StatusCodes.OK
-        responseAs[String] shouldBe "Server up and running"
-      }
-      Post("/") ~> BaseRoutes.baseRoutes ~> check {
-        status shouldBe StatusCodes.OK
-        responseAs[String] shouldBe "Server up and running"
-      }
-    }
-  }
-
-}
diff --git 
a/src/main/g8/src/test/scala/com/example/routes/SimpleRoutesSpec.scala 
b/src/main/g8/src/test/scala/com/example/routes/SimpleRoutesSpec.scala
deleted file mode 100644
index 0c38e13..0000000
--- a/src/main/g8/src/test/scala/com/example/routes/SimpleRoutesSpec.scala
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.example.routes
-
-import 
akka.http.scaladsl.marshallers.xml.ScalaXmlSupport.defaultNodeSeqUnmarshaller
-import akka.http.scaladsl.model.StatusCodes
-import akka.http.scaladsl.server.Route
-import akka.http.scaladsl.testkit.ScalatestRouteTest
-import org.scalatest.{ Matchers, WordSpec }
-
-import scala.xml.NodeSeq
-
-class SimpleRoutesSpec extends WordSpec with Matchers with ScalatestRouteTest 
with SimpleRoutes {
-
-  "SimpleRoute" should {
-    "answer to GET requests to `/hello`" in {
-      Get("/hello") ~> simpleRoutes ~> check {
-        status shouldBe StatusCodes.OK
-        responseAs[NodeSeq] shouldBe <html><body><h1>Say hello to 
akka-http</h1></body></html>
-      }
-    }
-    "not handle a POST request to `/hello`" in {
-      Post("/hello") ~> simpleRoutes ~> check {
-        handled shouldBe false
-      }
-    }
-    "respond with 405 when not issuing a GET to `/hello` and route is sealed" 
in {
-      Put("/hello") ~> Route.seal(simpleRoutes) ~> check {
-        status shouldBe StatusCodes.MethodNotAllowed
-      }
-    }
-  }
-
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to