Skip to content

API Reference

Complete API documentation for Laju Framework.

Overview

Laju provides a clean, type-safe API for building web applications. The framework is built on top of HyperExpress with additional utilities for common tasks.

Request Object

The Request object extends HyperExpress Request with additional properties.

Properties

PropertyTypeDescription
paramsRecord<string, string>URL parameters
queryRecord<string, string>Query string parameters
bodyanyRequest body (parsed JSON)
headersRecord<string, string>Request headers
cookiesRecord<string, string>Parsed cookies
userUser | undefinedAuthenticated user
sessionSession | undefinedSession data

Methods

request.json()

Parse JSON body asynchronously.

typescript
const body = await request.json();

request.file()

Get uploaded file.

typescript
const file = await request.file("avatar");

Response Object

The Response object extends HyperExpress Response with Laju-specific methods.

Methods

response.inertia(component, props)

Render an Inertia.js page.

typescript
return response.inertia("posts/index", {
  posts: posts,
  meta: { title: "Blog Posts" }
});

response.json(data)

Send JSON response.

typescript
return response.json({ success: true, data: posts });

response.redirect(url, status?)

Redirect to URL.

typescript
// 302 redirect (default)
return response.redirect("/posts");

// 303 redirect (after POST/PUT/DELETE)
return response.redirect("/posts", 303);

response.flash(type, message)

Set flash message.

typescript
return response
  .flash("success", "Post created!")
  .redirect("/posts");

response.status(code)

Set HTTP status code.

typescript
return response.status(404).json({ error: "Not found" });

Database (Kysely)

Laju uses Kysely for type-safe database queries.

Basic Queries

Select

typescript
// Select all
const posts = await DB.selectFrom("posts")
  .selectAll()
  .execute();

// Select specific columns
const posts = await DB.selectFrom("posts")
  .select(["id", "title", "created_at"])
  .execute();

// Select with where
const post = await DB.selectFrom("posts")
  .selectAll()
  .where("id", "=", id)
  .executeTakeFirst();

Insert

typescript
await DB.insertInto("posts").values({
  id: uuidv7(),
  title: "Hello World",
  content: "...",
  created_at: Date.now(),
}).execute();

Update

typescript
await DB.updateTable("posts")
  .set({ title: "Updated Title" })
  .where("id", "=", id)
  .execute();

Delete

typescript
await DB.deleteFrom("posts")
  .where("id", "=", id)
  .execute();

Joins

typescript
const posts = await DB.selectFrom("posts")
  .innerJoin("users", "posts.user_id", "users.id")
  .select([
    "posts.id",
    "posts.title",
    "users.name as author_name"
  ])
  .execute();

Ordering & Pagination

typescript
const posts = await DB.selectFrom("posts")
  .selectAll()
  .orderBy("created_at", "desc")
  .limit(10)
  .offset((page - 1) * 10)
  .execute();

Services

DB

Database service with Kysely.

typescript
import DB from "app/services/DB";

Authenticate

Authentication utilities.

typescript
import Authenticate from "app/services/Authenticate";

// Hash password
const hashedPassword = await Authenticate.hash("password123");

// Compare password
const isValid = await Authenticate.compare("password123", hashedPassword);

// Login user
return Authenticate.process(user, request, response);

Mailer

Email sending service.

typescript
import Mailer from "app/services/Mailer";

await Mailer.send({
  to: "user@example.com",
  subject: "Welcome",
  html: "<h1>Hello!</h1>"
});

Validator

Zod validation helper.

typescript
import Validator from "app/services/Validator";

const result = Validator.validate(schema, data);

if (!result.success) {
  return response.flash("error", result.errors[0]).redirect("/");
}

Middleware

Auth Middleware

Protect routes that require authentication.

typescript
import Auth from "app/middlewares/auth";

Route.get("/dashboard", [Auth], DashboardController.index);

Rate Limit Middleware

Limit request rate.

typescript
import { authRateLimit } from "app/middlewares/rateLimit";

Route.post("/login", [authRateLimit], LoginController.processLogin);

TypeScript Types

Request

typescript
import { Request } from "type";

class MyController {
  public async index(request: Request, response: Response) {
    // request has typed user property
    const userId = request.user?.id;
  }
}

Response

typescript
import { Response } from "type";

class MyController {
  public async index(request: Request, response: Response) {
    return response.inertia("page", {});
  }
}

Error Handling

typescript
try {
  // Your code
} catch (error: any) {
  console.error("Error:", error);
  
  if (error.code === "SQLITE_CONSTRAINT") {
    return response
      .flash("error", "Data already exists")
      .redirect("/", 303);
  }
  
  return response
    .flash("error", "Something went wrong")
    .redirect("/", 303);
}

Released under the MIT License.