GitHub
Backend Framework

HellcatAPI

A backend api framework build with java 17. Raw HTTP server — zero frameworks, zero abstraction layers. You write routes, HellcatAPI handles everything else.

Java 17+ Maven AGPL-3.0 No Frameworks SQLite / JDBC

Getting Started

HellcatAPI requires Java 17 or higher and Maven 3.6+. Clone the repository, configure your server, and run.

Requirements

Runtime

Java 17 or higher (LTS recommended). OpenJDK or any compatible JVM.

Build Tool

Apache Maven 3.6 or higher. All dependencies are resolved via pom.xml.

Database

SQLite is bundled by default. PostgreSQL or MySQL require a JDBC driver swap.

OS

Linux, macOS, or Windows. Works anywhere a JVM runs.

Build & Run

git clone https://github.com/MatrixTM26/HellcatAPI.git
cd HellcatAPI

mvn clean package -q
java -jar HellcatAPI.jar

Minimal Application

Everything starts from HellcatApp. Pass your secret key as the first argument.

HellcatApp App = new HellcatApp("your-secret-key");

App.Get("/hello", Req ->
    App.Json(Map.of("message", "Hello World"))
);

App.Run();
Default port: The server listens on 0.0.0.0:9926 unless overridden in server.properties.

Project Structure

All core logic lives under src/main/java/hellcat/core/. The entry point is TestApi.java.

app/

HellcatApp — main application class and entry point wrapper.

server/

Raw HTTP server, connection handler, and server logger.

router/

Route registration, matching, and path parameter parsing.

request/

Request parser, request object, and uploaded file model.

response/

Response builder and streaming response support.

middleware/

Middleware interface and all built-in middleware implementations.

template/

Lightweight Jinja2-like template engine.

db/

Database connection pool, query builder, and transaction context.

lib/

Logger utility and server config loader.

Configuration

Edit server.properties in the project root before running. All settings are optional — defaults are production-safe.

server.host=0.0.0.0
server.port=9926
server.debug=false
server.template.dir=templates
server.static.dir=static
server.static.url=/static
Key Default Description
server.host0.0.0.0Bind address for the HTTP server
server.port9926TCP port the server listens on
server.debugfalseEnable verbose debug logging (true / false)
server.template.dirtemplatesDirectory for HTML template files
server.static.dirstaticDirectory for static file assets
server.static.url/staticURL prefix for serving static files

Routing

Routes are registered on the HellcatApp instance. Handlers receive a HellcatRequest and must return a response object.

HTTP Method Shortcuts

App.Get("/hello", Req ->
    App.Json(Map.of("Message", "Hello World"))
);

App.Post("/echo", Req -> {
    Map<String, Object> Body = Req.GetJson();
    return App.Json(Body);
});

App.Put("/item", Req -> App.Json(Map.of("updated", true)));
App.Delete("/item", Req -> App.Json(Map.of("deleted", true)));
App.Patch("/item", Req -> App.Json(Map.of("patched", true)));

Path Parameters

Use <type:Name> syntax. Supported types: int, str, float, path.

App.Get("/users/<int:Id>", Req -> {
    int Id = Integer.parseInt(Req.PathParams.get("Id"));
    return App.Json(Map.of("Id", Id));
});

App.Get("/files/<path:FilePath>", Req -> {
    String FilePath = Req.PathParams.get("FilePath");
    return App.Text(FilePath, 200);
});

Multi-Method Route

App.Route("/multi", List.of("GET", "POST"), Req ->
    App.Json(Map.of("Method", Req.Method))
);

Middleware

Middleware intercepts every request before it reaches the route handler. Use built-in helpers or provide a custom lambda.

Built-in Middleware

// CORS — allow origins, credentials flag
App.UseCors(List.of("*"), false);

// Rate limiting — 100 requests per 60 seconds
App.UseRateLimit(100, 60);

// Adds security headers (X-Content-Type, X-Frame-Options, etc.)
App.UseSecurityHeaders();

// Gzip compress responses over 1024 bytes
App.UseGzip(1024);

// Reject bodies larger than 10 MB
App.UseBodySizeLimit(10 * 1024 * 1024);

Custom Middleware (Global)

App.UseMiddleware((Req, Next) -> {
    long Start  = System.currentTimeMillis();
    Object Resp = Next.apply(Req);
    System.out.println("Duration: " + (System.currentTimeMillis() - Start) + "ms");
    return Resp;
});

Route-Level Middleware

App.Post("/secure", Handler, List.of(RequireAuthMiddleware));
Middleware is executed in the order it is registered. Route-level middleware runs after all global middleware.

Request Object

Every route handler receives a HellcatRequest instance. It contains all parsed request data.

Fields

Req.MethodHTTP method string — "GET", "POST", "PUT", etc.
Req.PathRequest path — e.g. "/users/42"
Req.PathParamsMap of path parameter names to their string values
Req.QueryParamsMap of query string parameters — e.g. {"page": "1"}
Req.HeadersAll HTTP headers as a map with lowercase keys
Req.CookiesParsed cookie values as a String map
Req.BodyRaw request body as a byte array

Methods

Req.GetJson()                    // parse body as JSON → Map<String, Object>
Req.GetQuery("page", "1")        // query param with default fallback
Req.GetHeader("Authorization")   // get a specific request header
Req.GetRemoteIp()                // client IP address
Req.IsJson()                     // true if Content-Type is application/json
Req.IsForm()                     // true if Content-Type is application/x-www-form-urlencoded
Req.IsMultipart()                // true if Content-Type is multipart/form-data

Response Helpers

All response helpers are methods on the HellcatApp instance. Each returns a response object that the route handler must return.

MethodStatusDescription
App.Json(data)200JSON response from any object or Map
App.Json(data, 201)customJSON with explicit HTTP status code
App.Html(html)200Raw HTML string response
App.Text(text, 200)customPlain text response with status
App.Redirect(path)302HTTP redirect to another path
App.Redirect(path, 301)customRedirect with explicit status (301, 302, etc.)
App.Error(msg, 404)customJSON error with message and status
App.Error(msg, 422, details)customJSON error with additional detail map
App.File(path, name)200Serve a file as a download attachment
App.Stream(supplier, type)200Streaming response (SSE, chunked transfer)
App.Render(template, ctx)200Render a template with a context map

Usage Examples

App.Json(Map.of("status", "ok"))
App.Json(userList, 200)
App.Html("<h1>Hello</h1>")
App.Text("plain text", 200)
App.Redirect("/login")
App.Redirect("/login", 301)
App.Error("Not found", 404)
App.Error("Validation failed", 422, Map.of("field", "email"))
App.File("report.pdf", "download.pdf")
App.Stream(() -> chunks, "text/event-stream")
App.Render("index.html", Map.of("title", "HellcatAPI"))

Template Engine

HellcatAPI ships with a lightweight Jinja2-like template engine. Templates are stored in the templates/ directory and rendered with App.Render().

Rendering a Template

App.Get("/", Req ->
    App.Render("index.html", Map.of(
        "Title",   "HellcatAPI",
        "Message", "Server is running!"
    ))
);

Supported Syntax

TagDescription
{{ variable }}Output a variable value (HTML-escaped)
{{ object.field }}Output a nested object field
{{ value | raw }}Output raw HTML without escaping
{% if condition %} ... {% endif %}Conditional block
{% for item in items %} ... {% endfor %}Loop over a collection
{% extends "base.html" %}Extend a base template layout
{% block content %} ... {% endblock %}Define or override a named block
{% include "partial.html" %}Include another template file inline
{# comment #}Template comment — not rendered in output

Example Template

<!-- templates/index.html -->
{% extends "base.html" %}

{% block content %}
  <h1>{{ Title }}</h1>
  <p>{{ Message }}</p>

  {% if Users %}
    {% for User in Users %}
      <div>{{ User.Name }} — {{ User.Email }}</div>
    {% endfor %}
  {% endif %}
{% endblock %}

Database

HellcatAPI bundles SQLite via HellcatDB. Swap to PostgreSQL or MySQL by replacing the JDBC driver in pom.xml.

Initialization

Map<String, String> Migrations = new LinkedHashMap<>();
Migrations.put("001_create_users",
    "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)");

HellcatDB DB = new HellcatDB("app.db", 10, Migrations);
Migrations run automatically once on startup. Use a LinkedHashMap to ensure execution order. Keys are unique migration identifiers.

Query Builder

// Fetch all matching rows
DB.Table("users").WhereEq("role", "admin").OrderBy("id").All();

// Fetch the first matching row
DB.Table("users").WhereEq("id", 1).First();

// Count rows
DB.Table("users").Count();

// LIKE search with pagination
DB.Table("users").WhereLike("name", "%Tom%").Paginate(1, 20);

Write Operations

// Insert a row
DB.InsertRow("users", Map.of(
    "name", "Tom",
    "email", "tom@example.com"
));

// Update matching rows
DB.Table("users").WhereEq("id", 1).Update(Map.of("name", "Bob"));

// Delete matching rows
DB.Table("users").WhereEq("id", 1).Delete();

Transactions

try (HellcatTransactionContext Tx = DB.Transaction()) {
    Tx.Execute(
        "UPDATE products SET stock = stock - ? WHERE id = ?", 1, 5
    );
    long OrderId = Tx.Insert(
        "INSERT INTO orders (product_id, qty) VALUES (?, ?)", 5, 1
    );
    Tx.Commit();
}

JWT & Sessions

HellcatAPI includes built-in JWT signing/verification and a simple session system. The secret key is the one passed to HellcatApp.

JSON Web Tokens

// Sign a token with a payload, expiry in seconds
String Token = App.CreateJwt(
    Map.of("UserId", 1, "Role", "admin"),
    3600
);

// Verify and decode a token
Map<String, Object> Payload = App.DecodeJwt(Token);

Sessions

// Read session from request cookies
Map<String, Object> Session = App.GetSession(Req);

// Write session data into a response (null = use default expiry)
App.SaveSession(Response, Map.of("UserId", 1), null);
Sessions are cookie-based. The session data is signed with your app secret key. Pass an expiry in seconds as the third argument to SaveSession, or null for a browser-session cookie.

Sub-Routers

Group routes under a common prefix using HellcatRouter. Attach it to the main app with App.Include().

HellcatRouter Api = new HellcatRouter("/api/v1");

Api.Get("/health", Req ->
    App.Json(Map.of("Status", "ok"))
);

Api.Get("/users", Req ->
    App.Json(DB.Table("users").All())
);

Api.Post("/users", Req -> {
    Map<String, Object> Body = Req.GetJson();
    DB.InsertRow("users", Body);
    return App.Json(Map.of("created", true), 201);
});

App.Include(Api);

Routes registered on Api are resolved as /api/v1/health, /api/v1/users, etc.

Error Handlers

Register custom handlers for HTTP error codes. The handler receives the original request and the error object.

App.ErrorHandler(404, (Req, Err) ->
    App.Json(Map.of(
        "Error",   true,
        "Message", "Route not found",
        "Path",    Req.Path
    ), 404)
);

App.ErrorHandler(500, (Req, Err) ->
    App.Json(Map.of(
        "Error",   true,
        "Message", "Internal server error"
    ), 500)
);

App.ErrorHandler(429, (Req, Err) ->
    App.Json(Map.of(
        "Error",   true,
        "Message", "Rate limit exceeded"
    ), 429)
);

Full Reference

HellcatApp Methods

App.Get(path, handler)Register a GET route
App.Post(path, handler)Register a POST route
App.Put(path, handler)Register a PUT route
App.Delete(path, handler)Register a DELETE route
App.Patch(path, handler)Register a PATCH route
App.Route(path, methods, handler)Register a route for multiple methods
App.Include(router)Attach a HellcatRouter to the app
App.UseMiddleware(fn)Add a global middleware lambda
App.UseCors(origins, creds)Enable CORS middleware
App.UseRateLimit(max, window)Enable rate limiting middleware
App.UseSecurityHeaders()Add security HTTP headers to all responses
App.UseGzip(minSize)Enable Gzip compression for responses above threshold
App.UseBodySizeLimit(bytes)Reject requests with body larger than limit
App.ErrorHandler(code, fn)Register a handler for a specific HTTP status code
App.CreateJwt(payload, ttl)Sign and return a JWT string
App.DecodeJwt(token)Verify and decode a JWT string to a payload map
App.GetSession(req)Read session data from the request cookies
App.SaveSession(res, data, ttl)Write session data as a signed cookie
App.Run()Start the HTTP server (blocking call)

HellcatDB Methods

DB.Table(name)Begin a query against a named table
.WhereEq(col, val)Add a WHERE col = val clause
.WhereLike(col, pat)Add a WHERE col LIKE pattern clause
.OrderBy(col)Add an ORDER BY clause
.All()Execute and return all matching rows as a List of Maps
.First()Execute and return the first matching row as a Map
.Count()Return the count of matching rows
.Paginate(page, size)Return a page of results with LIMIT / OFFSET
.Update(data)Update matching rows with the provided map
.Delete()Delete all matching rows
DB.InsertRow(table, data)Insert a new row into a table
DB.Transaction()Open a transactional context (try-with-resources)

Dependencies

HellcatAPI intentionally keeps its dependency count minimal. Add these to your pom.xml.

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.17.0</version>
</dependency>

<dependency>
    <groupId>org.xerial</groupId>
    <artifactId>sqlite-jdbc</artifactId>
    <version>3.45.3.0</version>
</dependency>
PostgreSQL / MySQL: Replace the SQLite JDBC dependency with the appropriate driver. Update your connection string in HellcatDB accordingly. No other changes required.