The goal of this application is to show how common use-cases can be implemented with Spark:
- public web-service,
- web-services with restricted access (authentication required),
- CRUD.
This application use-case implementations are really simple ; be aware that in order to remain simple, some security issues were not addressed (encryption...).
Just launch the org.devteam.App
class and open http://localhost:4567/ in your browser.
If it is not already the case, you will also have to configure the annotation processor in your IDE : https://immutables.github.io/apt.html
- The
App
create an instance of the dependency graph (see [Dagger 2] (http://google.github.io/dagger/)) - The
Router
initialize all web application routes and starts the server - The server is up and running on port 4567
The great thing with Spark and Java 8 is the ability the compose actions very easily:
- Let's consider
get("/user", userWs::list)
: the actionuserWs::list
which list all the users is mapped to the path "/user" - Want to produce JSON ? No problem:
get("/user", jsonFilter.jsonResponse(userWs::list))
:jsonFilter.jsonResponse
is a simple function that takes a Route as parameter and returns a Route ; the returned Route just serializes the result of the Route taken as parameter in JSON - Want to restrict access to the web-service ?
get("/user", jsonFilter.jsonResponse(authenticationFilter.authenticate(userWs::list)))
: the authenticationFilter works the same as the jsonFilter ! - Almost all your actions are using JSON and authentication ? Factorize it all:
Route authenticatedAndJsonResponse(Route route) { return authenticationFilter.authenticate(jsonFilter.jsonResponse(route)); }
Even tough before and after filters are proposed by the framework, action composition enables the application to have a lot more flexibility: you can apply a filter to only certain actions. Moreover, it is easier to debug actions composition since you know exactly what you are doing.
- Spark launches fast ~ about 50ms
- Spark is fast : the overhead on top of Jetty is very small, Spark action execution is almost as fast as raw servlet
- Spark is simple : no reflection, no annotation, small library ; you will not encounter a lot of bad surprises using Spark
- Spark supports webSockets
- Spark supports an instance API:
Service.ignite().get("/api/hello", (request, response) -> "hello")
- Swagger cannot be easily integrated, see issue #258
- The current HTTP API is blocking: if you want to implement an asynchronous web-service, you will have a hard time
- The instance API is not yet fluent
- Microservices architecture
- Small web-application (small but fast!)
Since the version 2.4, Play Framework provides a way to embed the server in a simple Java application:
Server server = Server.forRouter(new RoutingDsl()
.GET("/hello/:to").routeTo(to ->
ok("Hello " + to)
)
.build()
);
This behavior enables to use Play with Maven (or Gradle/SBT...) in a similar way you would use Spark. That makes Play a very serious competitor to Spark since its API is non-blocking and it provides an instance API to configure the server. I plan to port this demo application to Play Framework to see how it compares to Spark :)
A real application will likely need other functionalities.
to provide a configuration functionality to a Spark application, a good choice would be the config library.
OkHttp and Retrofit target especially Android, however they also work great in any Java application.
A good alternative to JPA is jOOQ which enables to build type safe SQL queries. As a connection pool HikariCP seems to be the better at the moment.
Alternatively Plume Framework can be easily integrated to Spark (instead of Jersey which is provided by default). With Plume Framework these components will be optionally available:
- configuration,
- database querying,
- mail sending,
- scheduled tasks.