SkillAgentSearch skills...

Tiny

Tiny java web framework with lambda style composition of paths, filters, endpoints

Install / Use

/learn @paul-hammant/Tiny
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Tiny WebServer and WebSocketServer

A tiny web and socket server that depends only on JDK 21+ classes and are in a single source file: Tiny.java making a 53Kb jar. Just a fun pair-programmed project, really. Imperfectly pair-programmed with AIs. It is for use for to make small web/medium applications - perhaps not on the public web.

In a nutshell:

new Tiny.WebServer(Config.create().withWebPort(8080).withWebSocketPort(8081)) {{
    path("/shopping", () -> {

        filter(GET, ".*", (request, response, context) -> {
            // some logic then ..
            return FilterResult.STOP;
            // or maybe ...
            return FilterResult.CONTINUE; 
        });
    
        endPoint(GET, "/cart", (request, response, context) -> {
            // some logic for the url `/shopping/cart` .. maybe a list
            response.write("Cart contents ...\n");
            // write out cart contents
        });
    
        webSocket("/cartEvents", (message, sender, context) -> {
            sender.sendTextFrame("Sure, you'll be kept informed of inventory/price changes".getBytes("UTF-8"));
            // more logic to make that happen. See tests/WebSocketBroadcastDemo.java
        });
        
    });
}}.start();

You wouldn't inline those filter/endPoint/webSocket blocks though, you'd call methods.

Longer: The Tiny.java single source file provides a lightweight and flexible server implementation that supports both HTTP and WebSocket protocols. This single-source-file technology is designed to be easy to use and integrate into your projects.
It uses a Java 8 lambda syntax (@FunctionalInterface) as many newer web frameworks do. It also uses the virtual thread system in Java 21 and the JDK's built-in HTTP APIs rather than depending on Netty or Jetty.

License

Tiny.java is licensed under the MIT License - see the LICENSE file for details.

The tests are GPL

Web Server

The Tiny.WebServer class allows you to create an HTTP server with minimal configuration. You can define filters and endpoints for different HTTP methods (GET, POST, PUT, DELETE and others), and process requests.

The server supports:

  • Path-based Routing: Define endpoints with path parameters and handle requests dynamically. Paths can be nested to create a hierarchical structure, allowing for organized and intuitive filter/endpoint management.
  • Static File Serving: Serve static files from a specified directory with automatic content type detection.
  • Filters: Apply filters to requests for pre-processing or access control.
  • End Points: functional logic to respond to GET/POST/etc requests.
  • Fairly open

Filters and end-points can be at root level, or inside paths. Paths can be inside paths, too, but don't themselves and should only have other paths, filters, and endPoints within the block of code.

See path, filter and endPoint in the nutshell code above.

Web Sockets Server

A coupled Tiny.WebSocketServer class provides WebSocket support, enabling communication back from the server to attached clients. It can be used alone, but also integrated into the same path structure of the main server alongside endPoint and filter.

webSocket("/foo", (message, sender, context) -> {
    // logic
});

Rationale for Tiny

I wanted to make something that

  1. A reliance on Java-8's lambdas for base paths in particular - as close as regular Java can get to Groovy's builders for now. See the nutshell above.
  2. Support a multi-modular composition of a single served solution. This for web-module separation to aid deployment and testing flexibility

And in a second tier of "must have" features

  1. An attempt to coerce websockets into the same "nested path" composition
  2. No shared static state
  3. Aids testability wherever it can

And a third tier of admittedly gratuitous or pet-peeve wishes

  1. Exist in a single source file .. for no good reason.
  2. Does not itself pollute stdout or force a logging framework on users.
  3. Have no dependencies at all, outside the JDK

Single source file and no-maven used to be top level goals, but I am willing to admit that there is no strong rationale for those. They are firmly in the "let us see if that is possible" territory. At one stage there was no build file at all, (just copy-pastable javac, java commands), then there was a shell script, then there was a Makefile, which is where I should have started, but that's all moot now as there's a regular maven pom.xml

Table of Contents

User guide

"Users" are developers, if that is not obvious.

Basic Use

Intended use rests on the lambda expression introduced with Java 8.

End-points

Here is a basic example of defining a GET endpoint using Tiny WebServer:

Tiny.WebServer server = new Tiny.WebServer(Tiny.Config.create().withWebPort(8080)) {{
    endPoint(Tiny.HttpMethod.GET, "/hello", (req, res, context) -> {
        // req gives access to headers, etc
        res.write("Hello, World!");
    });
}}.start();

In this example, a GET endpoint is defined at the path /hello. When a request is made to http://localhost:8080/hello, the server responds with "Hello, World!"

A Filter and an End-point

Here's an example of using a filter with an endpoint in Tiny Web:

Tiny.WebServer server = new Tiny.WebServer(Tiny.Config.create().withWebPort(8080)) {{

    // Apply a filter to check for a custom header
    filter(Tiny.Method.GET, "/secure", (req, res, context) -> {
        if (!req.getHeaders().containsKey("X-Auth-Token")) {
            res.write("Unauthorized", 401);
            return FilterResult.STOP; // Stop processing if unauthorized
        }
        return FilterResult.CONTINUE; // Continue processing
    });

    // Define a GET endpoint
    endPoint(Tiny.Method.GET, "/secure", (req, res, context) -> {
        res.write("Welcome to the secure endpoint!");
    });
        
}}.start();

In this example, a filter is applied to the /secure path to check for the presence of an "X-Auth-Token" header. If the header is missing, the request is denied with a 401 status code. If the header is present, the request proceeds to the endpoint, which responds with "Welcome to the secure endpoint!".

Two End-points within a path

Here's an example of defining two endpoints within a single path using Tiny. Paths this way, were the reason for creating Tiny.

Tiny.WebServer server = new Tiny.WebServer(Tiny.Config.create().withWebPort(8080)) {{
    path("/api", () -> {
        // Define the first GET endpoint
        endPoint(Tiny.Method.GET, "/hello", (req, res, context) -> {
            res.write("{ message:`Hello from the first endpoint!` }");
        });

        // Define the second GET endpoint
        endPoint(Tiny.HttpMethods.GET, "/goodbye", (req, res, context) -> {
          res.write("{ message:`Goodbye from the second endpoint!` }");
        });
    });
}}.start();

A filter and an end-point within a path

Here's an example of using a filter to perform authentication and a logged-in user attribute to an endpoint within a path or not at all of there's no logged-in user.

Tiny.WebServer server = new Tiny.WebServer(Tiny.Config.create().withWebPort(8080).withWebSocketPort(-1)) {{
    path("/shopping", () -> {

        filter(Tiny.HttpMethods.GET, ".*", (req, res, context) -> {
            String allegedlyLoggedInCookie = req.getCookie("logged-in");
            // This test class only performs rot47 on the cookie passed in.
            // That's not secure in the slightest. See https://rot47.net/
            Authentication auth = IsEncryptedByUs.decrypt(allegedlyLoggedInCookie);
            if (!auth.authentic) {
                res.write("Try logging in again", 403);
                return FilterResult.STOP;
            } else {
                req.setAttribute("user", auth.user());
            }
            return FilterResult.CONTINUE; // Continue processing
        });
        endPoint(Tiny.Ht

Related Skills

View on GitHub
GitHub Stars6
CategoryDevelopment
Updated11mo ago
Forks1

Languages

Java

Security Score

62/100

Audited on Apr 14, 2025

No findings