io.joshworks.snappy:snappy

A tiny and powerful server for Java 8


Keywords
java-8, lambda, rest-server, server-sent-events, undertow, web-framework, web-server, websockets
License
Apache-2.0

Documentation

Snappy

A tiny and powerful web framework for Java 8

Features:

  • Based on Undertow handlers
  • Rest with content negotiation (media type only)
  • Server sent events
  • Server sent events client
  • Websockets
  • Websocket client
  • Built in simple service discovery
  • Small. ~6mb
  • No magic, plain and simple
  • Small memory footprint
  • Static files
  • Rest client
  • Multipart support
  • Executors and schedulers managed by the server
  • Extensible
  • Maven uber jar plugin using Spring boot

Maven setup

    <dependency>
        <groupId>io.joshworks.snappy</groupId>
        <artifactId>snappy</artifactId>
        <version>0.6.0</version>
    </dependency>
    

Import

import static io.joshworks.snappy.SnappyServer.*;
import static io.joshworks.snappy.http.Response.*;

Hello

public class App {

    public static void main(final String[] args) {
       get("/hello", req -> ok("Hello !", "txt")); //or text/plain
       start(); //9000
    }
}

Path parameter

public class App {

    public static void main(final String[] args) {
       get("/hello/{name}", req -> ok("Hello " + req.pathParameter("name"), "txt"));
       
       start();
    }
}

Receiving JSON

public class App {

    public static void main(final String[] args) {
       post("/users", req -> {
           User user = req.body().asObject(User.class);
           //..
           return ok();
       });
       
       start();
    }
}

Sending JSON

public class App {

    public static void main(final String[] args) {
       get("/users", req -> ok(new User("John Doe")));
       start();
    }
}

Filter

public class App {

    public static void main(final String[] args) {
        
       beforeAll("/users", req -> System.out.println("A")); 
       before("/users", req -> System.out.println("B")); 
       after("/users", (req, res) -> System.out.println("C")); 
       afterAll("/users", (req, res) -> System.out.println("D")); 
       
       get("/users", req -> {
           System.out.println("Users");
            return ok();
       });
               
       start();
        
        // Prints:
        //A
        //B
        //Users
        //C
        //D
    }
}

Error handling

public class App {

    public static void main(final String[] args) {
       
       exception(Exception.class, (ex, req) -> Response.internalServerError(ex));
       
       get("/users", exchange -> {
           throw new RuntimeException("Some error");
       });

       
       start();
    }
}

Serving static files

public class App {

    public static void main(final String[] args) {
        //from src/main/resources/static
        //available on /pages
        staticFiles("/pages");
        
//        staticFiles("/pages", "someFolder"); // src/main/resources/someFolder
    }
}

Uploading file

public class App {

    public static void main(final String[] args) {
        post("/fileUpload", req -> {
            Path theFile = req.multiPartBody("theFile").file().path();
            Files.copy(theFile, someOutputStream);
        });
    }
}

Broadcasting data with SSE

public class ClockServer {

    public static void main(final String[] args) {
            ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

            SseBroadcaster broadcaster =  sse("/clock");
            //curl http://localhost:9000/clock

            onStart(() -> scheduler.scheduleAtFixedRate(() -> broadcaster.broadcast(new Date().toString()), 1, 1, TimeUnit.SECONDS));
    
            start();
        }
}

SSE groups / topics

public class App {

    public static void main(final String[] args) {
        SseBroadcaster broadcaster = sse("/subscribe/{group}", sse -> {
            sse.joinGroup(sse.pathParameter("group"));
        });

        //curl http://localhost:9000/subscribe/group-a
        //curl http://localhost:9000/subscribe/group-b

        post("/publish/{group}", req -> {
            String group = req.pathParameter("group");
            String message = req.body().asString();
            broadcaster.broadcast(group, message);
            return ok();
        });
    }
}

Registering a parser

public class App {

    public static void main(final String[] args) {
       Parsers.register(myXmlParser);
       
       get("/xml", req -> ok("<root></root>"), produces("xml"));
       
    }
}

Resource group

public class App {

     public static void main(String[] args) {
            
        // /groupA/a
        // /groupA/b
        // /groupA/subgroup/c
        group("/groupA", () -> {
            get("/a", req -> {/* ... */});
            put("/b", req -> {/* ... */});

            group("/subgroup", () -> {
                get("/c", req -> {/* ... */});
            });
        });

        // /groupB/d
        group("/groupB", () -> {
            get("/d", req -> {/* ... */});
        });
        
        }
}

Uber jar

<build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
        <plugin>
            <groupId>io.joshworks.snappy</groupId>
            <artifactId>snappy-maven-plugin</artifactId>
            <version>0.5.2</version>
        </plugin>
    </plugins>
</build>