Skip to content
pcdvPublic

About

Minimalist web framework for Java (inspired by Flask)

Topics

Resources

Stars

49 stars

Watchers

5 watching

Forks

Latest commit

 

History

244 Commits

Folders and files

Repository files navigation

Flak - A lightweight and modular web framework for Java

Release build

Flak is a minimal but powerful framework for web applications and REST services. Its main philosophy is keeping boilerplate to a minimum. It runs either on the HttpServer embedded in the JDK, which costs no dependency at all, or on Netty.

Flak 3.0 and later require Java 17 or later. If you are stuck on an older JDK, the 2.x releases target Java 8.

It is composed of a generic API, two backends and some add-ons. In a minimal setup, on top of the JDK backend, the total size of dependencies is around 60KiB. If you need to implement a REST server and handle JSON data, you will have to add jackson-databind to your dependencies.

Flak components Description
flak-api Public API
flak-spi Internal API for service providers
flak-backend-jdk Binding for the web server included in the JDK
flak-backend-netty Binding for Netty, see Backends
flak-login Add-on for managing authentication, see Authentication
flak-jackson Add-on for conversion to/from JSON using Jackson, and for @QueryParams and @FormParams, see JSON
flak-swagger Add-on to generate OpenAPI specifications, see OpenAPI
flak-websocket Experimental add-on for websockets with the JDK backend, see WebSockets
flak-util Misc utilities: CORS, route dumper

Getting started

Add the API and a backend to build.gradle (the badge above shows the latest released version):

repositories {
  maven { url = "https://jitpack.io" }
}

dependencies {
  implementation "com.github.pcdv.flak:flak-api:3.2.1"

  // the backend, see Backends for the netty alternative
  runtimeOnly "com.github.pcdv.flak:flak-backend-jdk:3.2.1"
}

The following application outputs "Hello world!" on http://localhost:8080:

public class HelloWorld {
  @Route("/")
  public String helloWorld() {
    return "Hello world!";
  }

  public static void main(String[] args) throws Exception {
    App app = Flak.createHttpApp(8080);
    app.scan(new HelloWorld());
    app.start();
    Desktop.getDesktop().browse(new URI(app.getRootUrl()));
  }
}

Or if you like it compact:

public class HelloWorldCompact {
  public static void main(String[] args) throws Exception {
    Flak.createHttpApp(8080).scan(new Object() {
      @Route("/")
      public String helloWorld() {
        return "Hello world!";
      }
    }).start();
  }
}

A slightly bigger taste, with a path variable, a query parameter and JSON:

@Route("/api/users/:id/orders")
@JSON
public List<Order> orders(String id, @QueryParam(value = "limit", defaultValue = "20") int limit) {
  return store.orders(id, limit);
}

@Route("/api/users/:id/orders")
@Post
@JSON
public Order create(String id, Response r, Order order) {
  r.setStatus(201);
  return store.add(id, order);
}

Features

The documentation covers each of them in detail.

  • Routing: @Route on any public method, one annotation per HTTP method (@Post, @Put, @Patch, @Delete, @Head, @Options), path variables (/users/:id) and splats (/files/*path), prefixes, and the routes of an app listed at runtime
  • Handler arguments: path variables, typed @QueryParam with defaults, objects built from the whole query string with @QueryParams, Query, Form and objects built from it with @FormParams, Request, and arguments of your own types built by custom extractors
  • Responses: return a String, bytes, a stream or any object through a formatter, set the status and headers, redirect, stream chunked output or Server-Sent Events
  • Request bodies: streamed to the handler, with a size limit per app or per handler
  • Errors and hooks: throw an HttpException to answer with a status, error and success handlers, a handler for unknown URLs, hooks before every request
  • Compression: gzip, per handler or class
  • Several apps on one server, each under its own path, HTTPS, bind address, thread pool
  • JSON: @JSON converts arguments and return values with Jackson
  • Authentication: sessions, login page, @LoginRequired, permissions with @WithPermission, custom authentication schemes
  • Static resources: app.serveDir() and app.serveClasspath() serve files, optionally restricted to logged-in users
  • WebSockets, experimental: served on the routes of an app with the JDK backend, so that hooks and login apply to them, and dropped when the client is lost
  • CORS: let the pages of other origins call the app, preflight requests answered before routing and login checks
  • OpenAPI: generate a specification from the handlers
  • Plugins: installed automatically or listed explicitly, and easy to write
  • Two backends: the JDK's HttpServer or Netty, with the same code. Flak can also plug into a Netty server you own, next to websockets.

New in 3.0

Java 17, a complete Netty backend, streamed request bodies with size limits, route handlers that can be configured at runtime, typed query parameters, explicit plugin lists, and experimental websockets on the JDK backend. A few behaviours changed along the way, e.g. how + is decoded in query strings, and which of 401 and 403 flak-login sends. Migrating to 3.0 lists everything, with what to do about it.

Why Flak?

I'm a big fan of lightweight and simple. I've always liked the simplicity of Flask applications and missed an equivalent solution for Java. Most existing frameworks were very heavy in terms of dependencies (e.g. Play, Spring Boot, etc). Spark was a better fit but it brings ~2.5MiB of dependencies.

The JDK includes a HTTP server that is perfectly suited for serving small applications but its API is rather painful. Flak allows to leverage it with a friendly API, and the same application can run on Netty instead.

The API initially shared a lot of similarities with Flask:

  • route handlers are methods with annotations like @Route, @Post, @LoginRequired etc.
  • the request can be accessed through a ThreadLocal
  • user authentication is similar to flask-login

But now the style differs quite a bit since objects can be automatically passed in method arguments.

Build

Building Flak requires a JDK 17 or later. Everything else, including the Gradle distribution itself, is downloaded by the wrapper:

./gradlew build

The test suite runs against both backends: ./gradlew :flak-tests:test for the JDK one, ./gradlew :flak-tests:testNetty for Netty.

How to publish locally

If your project uses the local Ivy repository, run:

./gradlew publish -Pversion=3.0-SNAPSHOT

If your project uses the local Maven repository, run:

./gradlew publishToMavenLocal -Pversion=3.0-SNAPSHOT

Then use version 3.0-SNAPSHOT in your project dependencies.

About

Minimalist web framework for Java (inspired by Flask)

Topics

Resources

Stars

49 stars

Watchers

5 watching

Forks

Releases

Packages

Used by

Contributors

Languages