Let See Example
import {
compile_routes,
response,
Router,
} from "https://deno.land/x/[email protected]/mod.ts";
const _routes = [{
path: "/checlk",
handler: () => response.JSON("s"),
}, {
path: "/checldk",
method: "POST",
handler: () => response.JSON("s"),
}];
const routes = compile_routes(_route);
Deno.serve(
{ port: 3333 },
async (req: Request): Promise<Response> => {
return await new Router(routes).route(req);
}
);
If there is Method not present it get default to GET. If path is not there it will assume it is empty.
It is hardcore just /.+ where you need you get in pramas
const _routes = [{
path: "/.+",
handler: () => handler,
}];
You get params as array and you can get by params[0] , parmas[1]
handler(req:Request, params :any[]){
params[0];
}
Every Controller should return new Response.
(() => response.JSON("s"));
import { Session } from "./Session.ts";
export class response {
//JSON return a Json response with session regenrate the cookie id
//and set new cookie. as old one exipre after a request.
static async JSON(
body: any,
session?: Session,
status?: number,
header?: Record<string, string | null>,
) {
return new Response(JSON.stringify(body), {
status: status || 200,
headers: {
"content-type": "application/json; charset=utf-8",
...header,
...(session && session.reactiveSession().returnCookie()),
},
});
}
//JSONF return header and status with body
static async JSONF(
body: any,
header: Record<string, string | null> = {},
status?: number,
) {
return new Response(JSON.stringify(body), {
status: status || 200,
headers: {
"content-type": "application/json; charset=utf-8",
...header,
},
});
}
}
When I am trying to using URLPattern I see such a performace hit so it seem right choice is to create some light router faster then anyone.
It have Guard and a Router Config file
First Check little simple route
import {
compile_routes,
response,
Router,
} from "https://deno.land/x/[email protected]/mod.ts";
export const _routes: _Routes = [
{
path: "/text",
child: [
{
path: "/",
handler: () => response.JSONF("GET"),
},
{
method:"POST",
handler: () => response.JSONF("POST"),
}];
}
]
Method default is "GET" and path is "". So if you leave it blank you should know what you will get.
For Netested child / group / crud can use.
For Permission Guard , roles and islogin can used
We have two type of handler first for restrictive route and secound for public. with params
// raw request passto handler
export type CallbackHandler = (
request: Request,
params: any[],
) => Promise<Response>;
// Session pass to handler
export type CallbackHandlerLogin = (
session: Session,
params: any[]
) => Promise<Response>;
islogin default is false if your route is login protected you should put
{ path: "/login", handler: AuthController.Status, islogin: true },
{ path: "/login", method: "POST", handler: AuthController.Login },
{ path: "/logout", method: "GET", handler: AuthController.Logout, islogin: true },
{ path: "/register", method: "POST", handler: AuthController.Register },
when islogin is true we first check for cookie and if it is in session pass to handler. if not Error 401
You need to add Islogin to guard work.
if there is string it will return string as error 403.
guard?: () => Promise<false | string>;
export const AuthGuard = async (): Promise<false | string> => {
return await "Not Assesbile";
};
import { response } from "../../repo/response.ts";
import { compile_routes } from "../../repo/router.ts";
import { _Routes } from "../../repo/Type.ts";
export const _routes: _Routes = [
{
islogin: true,
path: "/login",
method: "GET",
handler: AuthController.Status,
guard: [AuthGuard],
},
];
islogin need to true to function
{
islogin: true,
path: "/login",
roles:['manager'],
child:[{
roles:['isuper'],
path:'/roles',
handler: AuthController.Status
}]
guard: [AuthGuard],
}
This is just a Group with CRUD functionallity but can used as desired
const user = [
{
path: "/user",
guard: [AuthGuard],
group: {
GET: [
{ path: "", handler: UserController.all, guard: [AdminGuard] },
{ path: "/.+", handler: UserController.show },
],
POST: [
{ path: "", handler: UserController.store },
{ path: "/.+", handler: UserController.update },
],
PATCH: [{ path: "", handler: UserController.upsert }],
DELETE: [{ path: "/.+", handler: UserController.delete }],
},
},
];
Crud has it meaning here is
['c','r','u','d','a','w','p']
c for create
r for read
u for update
d for delete
a for read all
w for read where
p is add in bulk
const user = {
path: "/user",
guard: [AuthGuard],
class:UserController,
crud: ['c','r','u','d','a','w','p']
};
it is usuall work like
{
GET: [
...user.crud.includes("a") &&
[{ path: "", handler: user.class.all }] || [],
...user.crud.includes("r") &&
[{ path: "/.+", handler: user.class.show }] || [],
],
POST: [
...user.crud.includes("c") &&
[{ path: "", handler: user.class.store }] || [],
...user.crud.includes("w") &&
[{ path: "where", handler: user.class.where }] || [],
...user.crud.includes("u") &&
[{ path: "/.+", handler: user.class.update }] || [],
],
PATCH: [
...user.crud.includes("p") &&
[{ path: "", handler: user.class.upsert }] || [],
],
DELETE: [
...crud.crud.includes("d") &&
[{ path: "/.+", handler: crud.class.delete }] || []
]
},
Yes i made sin to create new Method where
export const routes = compile_routes(_routes);
export type Routes = Record<string, Route[]>;
Router/Framework Flow
Documentation Update Soon Example as below
Model
import { Model } from '../../repo/Model.ts';
import { relation } from '../../repo/type.ts';
import { Account_attribute$ } from './Account_attribute.ts';
import { Account$ } from './Account.ts';
class Standard extends Model {
name = 'account_attribute_value';
table = 'account_attribute_values';
nullable: string[] = ["id"];
fillable: string[] = ['name','enable','account_attribute_id','account_id'];
model: string[] = ["name","enable","id","created_at","updated_at","account_attribute_id","account_id"];
relationship: Record<string, relation> = {'account_attribute':{'table':'account_attributes','name':'account_attribute_id','key':'id','callback':()=>Account_attribute$},'account':{'table':'accounts','name':'account_id','key':'id','callback':()=>Account$}};
}
export const Account_attribute_value$: Standard = new Standard().set('account_attribute_values');
Controller
import { response } from "../../../repo/response.ts";
import { Session } from "../../../repo/Session.ts";
import { Account_attribute_value$ } from "../../Model/Account_attribute_value.ts";
export class SuperAccount_attribute_valueController {
static async all(session: Session){
const account_attribute_value = await Account_attribute_value$.all().Item;
return response.JSON({ account_attribute_value }, session);
}
static async where(session: Session) {
const req = await Account_attribute_value$.where(await session.req.json()).Item;
return response.JSON({ req }, session);
}
static async show(session: Session, param: string[]) {
const req= await Account_attribute_value$.find(param[0].toString()).Item;
return response.JSON({req}, session);
}
static async store(session: Session){
const account_attribute_value = await Account_attribute_value$.create([await session.req.json()]);
return response.JSON({ account_attribute_value }, session);
}
static async update(session: Session, param: string[]) {
const account_attribute_value = await Account_attribute_value$.update(
[{ id: [param[0]] }],
await session.req.json(),
);
return response.JSON({ account_attribute_value }, session);
}
static async upsert(session: Session){
const account_attribute_value = await Account_attribute_value$.create(await session.req.json());
return response.JSON({ account_attribute_value }, session);
}
static async delete(session: Session, param: string[]) {
const account_attribute_value = await Account_attribute_value$.del([{ col: "id", value: [param[0]] }]);
return response.JSON({ account_attribute_value }, session);
}
}
This Framework can little hard but benefit in speed will unreal.
On Our Framework
Routing session and auth are good but testing is still lacking we are in still alpha
Running 10s test @ http://localhost:3333
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 397.97us 497.73us 9.72ms 97.06%
Req/Sec 14.48k 1.00k 16.18k 78.50%
288023 requests in 10.00s, 39.00MB read
Requests/sec: 28800.79
Transfer/sec: 3.90MB
When Oak
Running 10s test @ http://localhost:8080/
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 633.04us 0.98ms 31.01ms 97.65%
Req/Sec 8.79k 1.34k 14.73k 91.54%
188770 requests in 10.10s, 46.94MB read
Requests/sec: 17402.96
Transfer/sec: 4.65MB
Usually 33%++ faster then Oak