Home

Awesome

Minum Web Framework

When you need the fewest moving parts

The simplest Minum program (see more code samples below):

public class Main {
    public static void main(String[] args) {
        var minum = FullSystem.initialize();
        var wf = minum.getWebFramework();
        wf.registerPath(GET, "",
                r -> Response.htmlOk("<p>Hi there world!</p>"));
        minum.block();
    }
}

What is this?

This web framework, "Minum", provides a full-powered minimalist foundation for a web application. For TDD, by TDD.

Minum is five thousand lines of code - the "minimalist" competitors range from 400,000 to 700,000 lines when accounting for their dependencies. I have not found a similar project.

Applying a minimalist approach enables easier debugging, maintainability, and lower overall cost. Most frameworks trade faster start-up for a higher overall cost. If you need sustainable quality, the software must be well-tested and documented from the onset. As an example, this project's ability to attain such high test coverage was greatly enabled by the minimalism paradigm.

Getting Started

There is a 🚀 Quick start, or if you have a bit more time, consider trying the tutorial

Maven

<dependency>
    <groupId>com.renomad</groupId>
    <artifactId>minum</artifactId>
    <version>8.0.4</version>
</dependency>

Features:

Size Comparison:

Compiled size: 200 kilobytes.

Lines of production code (including required dependencies)

MinumJavalinSpring Boot
5,297141,0481,085,405

See details

Performance:

See framework performance comparison

Documentation:

Example projects demonstrating usage:

See the following links for sample projects that use this framework.

Smallest-possible

This project is valuable to see the minimal-possible application that can be made. This might be a good starting point for use of Minum on a new project.

<hr>

Example

This is a good example to see a basic project with various functionality. It shows many of the typical use cases of the Minum framework.

<hr>

Memoria project

This is a family-tree project. It demonstrates the kind of approach this framework is meant to foster.

Code samples

Instantiating a new database:

var db = new Db<>(foosDirectory, context, new Foo());

Adding a new object to a database:

var foo = new Foo(0L, 42, "blue");
db.write(foo);    

Updating an object in a database:

foo.setColor("orange");
db.write(foo);    

Deleting from a database:

db.delete(foo);    

Writing a log statement:

logger.logDebug(() -> "hello");

Parsing an HTML document:

List<HtmlParseNode> results = new HtmlParser().parse("<p></p>");

Searching for an element in the parsed graph:

HtmlParseNode node;
List<HtmlParseNode> results = node.search(TagName.P, Map.of());

Creating a new web handler (a function that handles an HTTP request and returns a response):

public Response myHandler(Request r) {
  return Response.htmlOk("<p>Hi world!</p>");
}

Registering that endpoint:

webFramework.registerPath(GET, "formentry", sd::formEntry);

Building and rendering a template:

TemplateProcessor foo = TemplateProcessor.buildProcessor("hello {{ name }}");
String rendered = foo.renderTemplate(Map.of("name", "world"));

Getting a query parameter from a request:

String id = r.requestLine().queryString().get("id");

Getting a body parameter from a request, as a string:

String personId = request.body().asString("person_id");

Get a path parameter from a request as a string:

Pattern requestRegex = Pattern.compile(".well-known/acme-challenge/(?<challengeValue>.*$)");
final var challengeMatcher = requestRegex.matcher(request.requestLine().getPathDetails().isolatedPath());
// When the find command is run, it changes state so we can search by matching group
if (! challengeMatcher.find()) {
    return new Response(StatusLine.StatusCode.CODE_400_BAD_REQUEST);
}
String tokenFileName = challengeMatcher.group("challengeValue");

Getting a body parameter from a request, as a byte array:

byte[] photoBytes = body.asBytes("image_uploads");

Checking for a log message during tests:

assertTrue(logger.doesMessageExist("Bad path requested at readFile: ../testingreadfile.txt"));