Tina4 Node.js -- Quick Reference
🔥 Hot Tips
- Routes go in
src/routes/, templates insrc/templates/, static files insrc/public/ - GET routes are public by default; POST/PUT/PATCH/DELETE require a token
- Return an object from
response()and the framework auto-setsapplication/json - Use
tina4 startto launch the dev server on port 7145 - Node.js 22+ required (uses built-in
node:sqlite)
Installation
Four commands. The server starts and your browser shows the result.
npm install tina4-nodejs
tina4 init my-project
cd my-project
tina4 startBasic Routing
Define a path. Write a handler. The framework maps requests to your code.
import { get, post } from "tina4-nodejs";
get("/", async (request, response) => {
return response("<h1>Hello Tina4 Node.js</h1>");
});
post("/api", async (request, response) => {
return response({ data: request.params });
});Middleware
Middleware runs before and after your route handlers. Use it for logging, auth checks, or request transformation.
import { get, middleware } from "tina4-nodejs";
class LogMiddleware {
static beforeRequest(request, response) {
console.log("Before:", request.url);
return [request, response];
}
static afterRequest(request, response) {
console.log("After:", request.url);
return [request, response];
}
}
middleware(LogMiddleware);
get("/protected", async (request, response) => {
return response("Protected route");
});Template Rendering
Place .twig files in ./src/templates and static assets in ./src/public. The engine reads your template, fills in the variables, and delivers clean HTML.
<!-- src/templates/index.twig -->
<h1>Hello {{name}}</h1>import { get } from "tina4-nodejs";
get("/", async (request, response) => {
return response.render("index.twig", { name: "World!" });
});Authentication
POST, PUT, PATCH, and DELETE routes require a bearer token by default. Pass Authorization: Bearer API_KEY in your request headers. Check .env for the default API_KEY.
import { get, post, noAuth, secured } from "tina4-nodejs";
post("/login", noAuth(), async (request, response) => {
return response("Logged in");
});
get("/protected", secured(), async (request, response) => {
return response("Welcome!");
});Databases
One line connects to your database. The fetch method returns results with built-in pagination.
import { Database } from "tina4-nodejs";
const dba = new Database("sqlite3:data.db");
const result = await dba.fetch("SELECT * FROM users", { limit: 10 });ORM
Define your model as a class. Fields map to columns. The ORM handles create, read, update, and delete.
import { ORM, IntegerField, StringField } from "tina4-nodejs";
class User extends ORM {
id = IntegerField({ primaryKey: true, autoIncrement: true });
name = StringField();
}
await new User({ name: "Alice" }).save();
const user = new User();
await user.load("id = ?", [1]);CRUD
One method generates a full CRUD interface from your ORM model. Bind it to a template and the grid renders itself.
import { get } from "tina4-nodejs";
get("/users/dashboard", async (request, response) => {
const users = new User().select("id, name, email");
return response.render("users/dashboard.twig", { crud: users.toCrud(request) });
});Migrations
Create a migration file with the CLI. Write your SQL. Run the migration. The framework tracks what has run.
tina4 migrate:create create_users_table-- migrations/00001_create_users_table.sql
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT
);tina4 migrateOpenAPI and Swagger UI
Add a description to your route. Visit http://localhost:7145/swagger. Your API documentation appears, ready to share.
import { get, description } from "tina4-nodejs";
get("/users", description("Get all users"), async (request, response) => {
return response(new User().select("*"));
});Queues
Produce messages to a topic. Consume them asynchronously. The queue handles retries and ordering.
import { Queue, Producer, Consumer } from "tina4-nodejs";
const queue = new Queue({ topic: "emails" });
new Producer(queue).produce({ to: "alice@example.com", subject: "Welcome" });
const consumer = new Consumer(queue);
for await (const msg of consumer.messages()) {
console.log(msg.data);
}WebSockets
Open a connection. Listen for messages. Send responses. The WebSocket handles the protocol, the handshake, and the keepalive.
import { get, WebSocket } from "tina4-nodejs";
get("/ws/chat", async (request, response) => {
const ws = await new WebSocket(request).connection();
ws.on("message", async (data) => {
await ws.send(`Echo: ${data}`);
});
return response("");
});