Soklet Logo

A virtual-threaded Java HTTP server with zero dependencies.

Soklet lets you create web services with modern features and minimal ceremony. Codes like a library, not a framework.

ExampleResource.java
// Enjoy statically-typed request handlers.
@GET("/hello/{date}")
String hello(@PathParameter LocalDate date) {
return String.format("Hello on %s!", date);
}
// Your upstream code parses requests.
// Your downstream code writes responses.
// Your logic stays isolated and easily testable.
// JSON, XML, or something else? It's your call.
record Toy(String name, Double price) {}
@POST("/toy-sales")
Map<String, Double> sales(@RequestBody List<Toy> toys) {
return toys.stream().collect(
Collectors.groupingBy(
Toy::name,
Collectors.summingDouble(Toy::price)));
}

Overview

Why Soklet?

The Java web ecosystem is missing a server solution that is dependency-free but offers support for Virtual Threads, Server-Sent Events, hooks for dependency injection, and annotation-based request handling. Soklet aims to fill this void.

Soklet provides the basic plumbing to build "transactional" REST APIs that exchange small amounts of data with clients. It does not make technology choices on your behalf (but an example of how to build a full-featured API is available). It does not natively support Reactive Programming or similar methodologies. It does give you the foundation to build your system, your way.

Soklet is commercially-friendly Open Source Software, proudly powering production systems since 2015.


Design Goals

Design Non-Goals

  • SSL/TLS (your load balancer should provide TLS termination)
  • Traditional HTTP streaming
  • WebSockets
  • Dictate which technologies to use (Guice vs. Dagger, Gson vs. Jackson, etc.)
  • "Batteries included" authentication and authorization

Installation

Soklet is a single JAR, available on Maven Central.

JDK 17+ is required (or JDK 21+ for Server-Sent Events).

Maven

<dependency>
  <groupId>com.soklet</groupId>
  <artifactId>soklet</artifactId>
  <version>2.0.0</version>
</dependency>

Gradle

repositories {
  mavenCentral()
}

dependencies {
  implementation 'com.soklet:soklet:2.0.0'
}

Direct Download

If you don't use Maven or Gradle, you can drop soklet-2.0.0.jar directly into your project. No other dependencies are required.

Example Usage

Here we demonstrate building and running a single-file Soklet application with nothing but the soklet-2.0.0.jar and the JDK. There are no other libraries or frameworks, no Servlet container, no Maven build process - no special setup is required.

While a real production system will have more moving parts, this demonstrates that you can build server software without ceremony or dependencies.

Source Code

package com.soklet.example;

public class App {
  // Canonical example
  @GET("/")
  public String index() {
    return "Hello, world!";
  }
  
  // Echoes back the path parameter, which must be a LocalDate
  @GET("/echo/{date}")
  public LocalDate echo(@PathParameter LocalDate date) {
    return date;
  }

  // Formats request body locale for display and customizes the response.
  // Example: fr-CA ⇒ francês (Canadá)
  @POST("/language")
  public Response languageFor(@RequestBody Locale locale) {
    Locale systemLocale = Locale.forLanguageTag("pt-BR");
    String contentLanguage = systemLocale.toLanguageTag();

    return Response.withStatusCode(200)
      .body(locale.getDisplayName(systemLocale))
      .headers(Map.of("Content-Language", Set.of(contentLanguage)))
      .cookies(Set.of(
        ResponseCookie.withName("lastRequest")
          .value(Instant.now().toString())
          .httpOnly(true)
          .secure(true)
          .maxAge(Duration.ofMinutes(5))
          .sameSite(SameSite.LAX)
          .build()
      ))        
      .build();
  }

  // Start the server and listen on :8080
  public static void main(String[] args) throws Exception {
    // Use out-of-the-box defaults
    SokletConfig config = SokletConfig.withServer(
      Server.withPort(8080).build()
    ).build();

    try (Soklet soklet = Soklet.withConfig(config)) {
      soklet.start();
      System.out.println("Soklet started, press [enter] to exit");
      soklet.awaitShutdown(ShutdownTrigger.ENTER_KEY);
    }
  }
}

Want a better understanding of Soklet's capabilities? Start with Request Handling.

Want a minimum-viable "hello world" app you can easily clone and run? Check out the Barebones App.

Want to see how a real-world Soklet app looks? The Toy Store App covers topics like JSON marshaling, dependency injection, authentication/authorization, talking to a database, error handling, internationalization, and more.

Building and Running

You'll need to provide javac with these flags:

  • -parameters
  • -processor com.soklet.SokletProcessor

JDK 17+ is required.

If you need a JDK, Amazon provides Corretto - a free-to-use-commercially, production-ready distribution of OpenJDK that includes long-term support. Official Corretto Docker Images are also available.

It's recommended to use JDK 21+ to take advantage of Virtual Threads.

Where's Maven? Where's Gradle?

The examples below use javac to build and java to run. Soklet systems can be structurally as simple as a "hello world" app.

Of course, most systems use a build tool to manage dependencies and execution. The Toy Store App shows how a Maven pom.xml can be configured for Soklet.

Build

% javac -parameters -cp soklet-2.0.0.jar -processor com.soklet.SokletProcessor -d build src/com/soklet/example/App.java

Run

% java -cp soklet-2.0.0.jar:build com/soklet/example/App

Test

# Hello, world
% curl -i 'http://localhost:8080/'
HTTP/1.1 200 OK
Content-Length: 13
Content-Type: text/plain; charset=UTF-8
Date: Sun, 21 Mar 2024 16:19:01 GMT

Hello, world!
# Acceptable path parameter
% curl -i 'http://localhost:8080/echo/2024-12-31' 
HTTP/1.1 200 OK
Content-Length: 10
Content-Type: text/plain; charset=UTF-8
Date: Sun, 21 Mar 2024 16:19:01 GMT

2024-12-31
# Illegal path parameter
% curl -i 'http://localhost:8080/echo/abc'
HTTP/1.1 400 Bad Request
Content-Length: 21
Content-Type: text/plain; charset=UTF-8
Date: Sun, 21 Mar 2024 16:19:01 GMT

HTTP 400: Bad Request
# Language request body
% curl -i -X POST 'http://localhost:8080/language' -d 'fr-CA'
HTTP/1.1 200 OK
Content-Language: pt-BR
Content-Length: 18
Content-Type: text/plain; charset=UTF-8
Date: Sun, 21 Mar 2024 16:19:01 GMT
Set-Cookie: lastRequest=2024-04-21T16:19:01.115336Z; Max-Age=300; Secure; HttpOnly; SameSite=Lax

francês (Canadá)

Credits

Soklet stands on the shoulders of giants. Internally, it embeds code from the following OSS projects, all of which have licenses that are suitable for commercial use:

Do Zero-Dependency Libraries Interest You?

Similarly-flavored commercially-friendly OSS libraries are available.

  • Pyranid is a modern JDBC interface that embraces SQL - not an ORM
  • Lokalized enables natural-sounding translations (i18n) via an expression language