Spur Framework
A Sinatra inspired library for building REST microservices in Java 8. Spur for the cowboy in us!
Lightweight, at 4.6MB in size.
Simple
package com.example;
import com.clianz.spur.SpurServer;
public class BasicExample {
    public static void main(final String[] args) {
        new SpurServer()
            .get("/", (req, res) -> res.send("Hello World"))
            .start();
   }
} 
Non-Blocking by Default
The server is build around single-threaded event loop by default (reactive pattern).
IMPORTANT: Do not block the thread!
- JDBC queries are blocking by default, look into NoSQL with an async clients instead.
 - Watchout for synchronous HTTP client, pick an async one instead.
 
If blocking code is necessary, it can still be enabled through options.
server.start(new SpurOptions().enableBlockableHandlers(false) 
Request Validator Built-in
Declare the model with Bean Validator 1.1 tags.
public class Car {
    @Min(1)
    private int doors;
    private String name;
    ...
} 
Any HTTP request body of this type will trigger the validation automatically.
Request/Response JSON Marshaling/Unmarshaling
Server will automatically parse to/from JSON:
new SpurServer()
        .post("/test-drive", Car.class, (req, res) -> {
            Car car = req.body();
            log.info("Validated with Bean Validator 1.1: " + car.getName());
            log.info("Sending request body back as response.");
            res.send(car);
        })
        .start(); 
Simple Scheduler
server.schedule(60, () -> LOGGER.info("This is a runnable task that triggers every 60 seconds")); 
Server Side Event (SSE) Support
server.sse("/sse");
server.broadcastSse("/sse", "A Server-Sent-Event (SSE) to everyone listening for events on the endpoint.");
server.schedule(5,
        () -> server.broadcastSse("/sse", sseConn -> sseConn.send("Constant spam, by SSE"))); 
Web-Socket Support
server.websocket("/myapp", res -> {
    LOGGER.info("[OnConnectEvent] A user has connected");
    res.send("Welcome!");
}, (msg, res) -> {
    LOGGER.info("[OnMessageEvent] User message received: " + msg);
    res.send("I heard you say: " + msg);
});
server.broadcastWebsockets("/myapp", "Everyone connected to the websocket path /myapp will see this");
server.broadcastWebsockets("/myapp",
        "This message will broadcast to websocket users on the path /myapp only if the predicate operator on the key's value is true",
        "attrKey", attrVal -> attrVal != null); 
HTTP Request Filter/Validator
Since this library does not support sessions by design, JWT should be used for auth.
Filter/pre-request validator may be used for this:
server.preFilterRequests(req -> !req.header("deny")
        .isPresent(), res -> res.status(StatusCodes.FORBIDDEN)
        .send()); 
Note: This is not applicable web-sockets or SSE.
Other Server Options
Some other options that can be configured via server.start(new SpurOptions()...)
- forceHttps
 - enableCorsHeaders
 - enableBlockableHandlers
 - enableGzip
 - gzipMaxSize
 - enableBasicAuth
 - host
 - port
 - enableHttps
 - sslContext (required when using https)
 - httpsPort
 - enableHttp2 (only with https)
 - requestParseTimeOut
 - maxEntitySize
 
Examples
See: Examples code
Complete sample project: https://github.com/icha024/spur-example