@webtypen/webframez-core
v0.3.30
Published
The core package of the typescript based webframez (web-framework) by webtypen.de
Readme
@webtypen/webframez-core
TypeScript-first backend framework core for Node.js.
This README reflects the current API in this repository and focuses on:
- Routing
- Datatables
- DataBuilder
- Console Commands
- Queue and Jobs
Requirements
- Node.js
>= 20(recommended) - TypeScript for development
Installation
npm i @webtypen/webframez-coreBasic Web Setup
import { BaseKernelWeb, Request, Response, Route, WebApplication } from "@webtypen/webframez-core";
class Kernel extends BaseKernelWeb {
static controller = {
TestController: class {
async index(req: Request, res: Response) {
return res.send({ status: "ok" });
}
}
};
static middleware = {
auth: async (next: Function, reject: Function, req: Request, res: Response) => {
const isAllowed = true;
if (!isAllowed) {
return reject(new Error("Unauthorized"));
}
next(true);
}
};
}
const app = new WebApplication();
app.boot({
kernel: Kernel,
port: 3000,
basename: null,
routesFunction: () => {
Route.get("/", "TestController@index");
}
});WebApplication.boot(...) supports:
kernelportbasenameroutesFunctionmodulesconfigdatatablesjobsmodeonBoot
Routing
Register Routes
Route.get("/", "HomeController@index");
Route.post("/login", "AuthController@login");
Route.put("/users/:id", "UserController@update");
Route.delete("/users/:id", "UserController@delete");You can also register inline handlers:
Route.get("/health", (req: Request, res: Response) => {
return res.send({ status: "ok" });
});Path Parameters and Wildcards
Supported path patterns:
- Required parameter:
/:id - Optional parameter:
/:id? - Single wildcard:
/* - Catch-all wildcard:
/**
Matched values are available in req.params.
Route Groups
Route.group({ prefix: "/admin", middleware: ["auth"] }, () => {
Route.get("/dashboard", "AdminController@dashboard");
Route.group({ prefix: "/users" }, () => {
Route.get("/:id", "AdminUserController@details");
});
});Route Middleware
Attach middleware by key via route options:
Route.get("/me", "AccountController@me", { middleware: ["auth"] });Middleware signature:
(next, reject, req, res) => {
// allow:
next(true);
// abort with error:
// reject(new Error("Forbidden"));
}Extend the Route Facade
You can add custom route registration helpers:
Route.extend("jsonGet", (route) => {
return (path: string, component: any, options?: any) => {
route.get(path, async (req: Request, res: Response) => {
res.header("Content-Type", "application/json");
return component(req, res);
}, options);
};
});
(Route as any).jsonGet("/x", (req: Request, res: Response) => res.send({ ok: true }));Request and Response
Request
Request includes:
method,url,headers,rawHeadersbody,bodyPlainquery,queryRawparamsfilesmessage(nativeIncomingMessage)
Response
Common helpers:
res.status(201);
res.header("X-Test", "1");
res.send({ status: "success" });Also available:
sendCsv(...)download(filepath, options?)stream(req, filepath, filename, mimeType)registerEvent("after", fn)
Datatables
Use Datatable + DatatableRegistry + DatatableController.
Define a Datatable
import { Datatable, Request } from "@webtypen/webframez-core";
export class UsersTable extends Datatable {
collection = "users";
perPage = 25;
columns = {
name: { label: "Name" },
email: { label: "E-Mail" }
};
filter = {
name: { type: "text", mapping: "name" }
};
aggregation = async (req: Request) => {
return [{ $sort: { created_at: -1 } }];
};
}Register Datatables
app.boot({
// ...
datatables: {
users: UsersTable
}
});Datatable Endpoints
Use DatatableController in your routes:
import { DatatableController, Route } from "@webtypen/webframez-core";
Route.post("/api/datatable", "DatatableController@restApi");
Route.post("/api/datatable/export", "DatatableController@tableExport");restApi supports:
- init requests (
init_request) - paginated data
- selectable functions (
apiFunction)
tableExport uses your table exports definition.
DataBuilder
Use DataBuilder + DataBuilderController for schema-driven CRUD flows.
Define and Register Types
import { DataBuilder } from "@webtypen/webframez-core";
const builder = new DataBuilder();
builder.registerType({
key: "user",
singular: "User",
plural: "Users",
schema: {
version: "1.0.0",
collection: "users",
fields: {
email: { type: "text", required: true, unique: { match: {} } },
age: { type: "integer" }
}
}
});You can also use:
registerModelType(...)registerFieldType(...)
Expose the REST API
import { DataBuilderController, Route } from "@webtypen/webframez-core";
class MyDataBuilderController extends DataBuilderController {
constructor() {
super(builder);
}
}
// Register controller in kernel, then:
Route.post("/api/builder", "MyDataBuilderController@restApi");__builder_rest_api actions:
typedetailsdetails-newdatasavedeleteapi-autocomplete
Console Commands
Use ConsoleApplication with BaseKernelConsole.
import { BaseKernelConsole, ConsoleApplication, ConsoleCommand } from "@webtypen/webframez-core";
class HelloCommand extends ConsoleCommand {
static signature = "hello";
static description = "Print a greeting";
async handle() {
this.success("Hello world");
}
}
class KernelConsole extends BaseKernelConsole {
static commands = [HelloCommand];
}
const app = new ConsoleApplication();
app.boot({
kernel: KernelConsole,
config: {}
});ConsoleCommand helpers include:
getArguments(),getOptions(),getOption(...)ask(...)write,writeln,info,warning,success,error- progress helpers (
progress,progressIncrement,progressFinish)
Queue and Jobs
Queue workers run through console commands and use queue_jobs storage.
Create a Job
import { BaseQueueJob } from "@webtypen/webframez-core";
export class SendMailJob extends BaseQueueJob {
async handle(job: any) {
this.log("Sending mail", job.payload);
// do work...
// optional delayed re-run:
// return this.executeAgain(5, "minutes");
}
}Create a new queue entry:
await SendMailJob.create({
payload: { userId: "..." },
priority: 5,
worker: null
});Register Jobs
app.boot({
// ConsoleApplication or WebApplication
jobs: [SendMailJob]
});Queue Config
Configure workers in config.queue:
export default {
workers: {
default: {
is_active: true,
jobclasses: ["SendMailJob"],
automation: [
{
jobclass: "SendMailJob",
executions: [
["every_x_mins", 15],
["daily", "08:00"],
["every_hour", 5],
["mondays", "09:30"]
]
}
]
}
}
};Built-in Queue Commands
queue:startqueue:statusqueue:stopqueue:logqueue:workerqueue:worker:autorestart
Additional built-in command:
build
Modules
You can load module providers via modules in WebApplication.boot(...).
A module provider can:
- register controllers/middleware
- define
boot() - define
routes()
Lambda Mode
LambdaApplication uses the same router in AWS Lambda mode:
import { LambdaApplication } from "@webtypen/webframez-core";
const app = new LambdaApplication();
export const handler = (event: any, context: any) => {
return app.boot(event, context, {
kernel: Kernel,
routesFunction: () => {
Route.get("/status", (req, res) => res.send({ ok: true }));
}
});
};