Skip to content

Commit c967ba7

Browse files
authored
feat: class-base controllers added to AxonCore.
Feat class base controllers
2 parents 75213c3 + 54b3ed9 commit c967ba7

15 files changed

Lines changed: 280 additions & 26 deletions

File tree

README.md

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,37 @@ Currently Axon is 2X faster than Express. :D please checkout [Axon Benchmarks](.
1010

1111
[Axon telegram channel](https://t.me/axonjs)
1212

13-
Latest change: (v0.10.0)
13+
Latest change: (v0.11.0)
14+
- Class-Based Controllers
15+
You can use the new generation of controllers in Axon.
16+
In class-based controllers you can use state managing of classes in your application without any instance making.
17+
More organized controllers!
18+
```ts
19+
class UsersController extends BaseController {
20+
async index(req: Request<any>, res: Response) {
21+
return res.status(200).body({});
22+
}
23+
}
24+
25+
// [Class, Method]
26+
router.get("/users", [UsersController, "index"]);
27+
```
28+
29+
Your controller class must extends from BaseController, Otherwise the router will throw error.
30+
```ts
31+
class UsersController {
32+
async index(req: Request<any>, res: Response) {
33+
return res.status(200).body({});
34+
}
35+
}
36+
37+
router.get("/users", [UsersController, "index"]);
38+
39+
// Error: Controller class must extends from BaseController
40+
```
41+
42+
Past changes:
43+
#### (v0.10.0)
1444
- Cookie manager added to Axon.
1545
You can access cookie manager by importing AxonCookie class in your code.
1646
AxonCookie has some static methods for managing cookies easily.
@@ -22,8 +52,7 @@ Latest change: (v0.10.0)
2252
AxonCookie.parse(req);
2353
AxonCookie.clear(res, name, options);
2454
```
25-
26-
Past changes: (v0.9.0)
55+
#### (v0.9.0)
2756
- Plugin system updated.
2857
- Project environment state added to core config.
2958
- Validation system added to router.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { BaseController } from "../../../src";
2+
import type { Response, Request } from "../../../src";
3+
4+
class AuthController extends BaseController {
5+
async login(req: Request<any>, res: Response) {
6+
res.status(200).body({
7+
msg: "Axon Class-based Controller 🤙"
8+
});
9+
}
10+
}
11+
12+
export default AuthController;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Axon } from "../../src";
2+
import authRouter from "./routers/auth.route";
3+
4+
const core = Axon();
5+
6+
core.loadRoute(authRouter);
7+
8+
core.listen();
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Router } from "../../../src";
2+
import AuthController from "../controllers/auth.controller";
3+
4+
const router = Router("/api/auth");
5+
6+
router.post("/login", [AuthController, "login"]);
7+
8+
export default router;

examples/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
*/
44

55
import { Axon, Request, Response, NextFunc, axonLogger, Middleware} from "../src";
6-
import { v1Routes } from "./routes/v1";
7-
import { v2Routes } from "./routes/v2";
6+
import { v1Routes } from "./routers/v1";
7+
import { v2Routes } from "./routers/v2";
88
import { LogPluginTest } from "./plugins/log"
99

1010
const core = Axon()

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@axonlabs/core",
3-
"version": "0.10.0",
3+
"version": "0.11.0",
44
"description": "A backend library that aims to be simple and powerful.",
55
"author": "Mr.MKZ",
66
"license": "ISC",

src/Router/AxonRouter.ts

Lines changed: 88 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import { FuncController, Middleware, RouteParams, HttpMethods, MiddlewareStorage
44
import { logger } from "../core/utils/coreLogger";
55
import { resolveConfig } from "../core/config/AxonConfig";
66
import { AxonValidator } from "../core/validation/AxonValidator";
7-
import type { ValidationObj } from "../types/RouterTypes";
7+
import type { ClassController, ValidationObj } from "../types/RouterTypes";
8+
import { BaseController } from "../core/classController";
89

910
const duplicateError = (path: string, method: keyof HttpMethods) => {
1011
throw new RouterException({
@@ -17,15 +18,15 @@ const duplicateError = (path: string, method: keyof HttpMethods) => {
1718
})
1819
}
1920

20-
let MIDDLEWARE_TIMEOUT: number;
21+
let MIDDLEWARE_TIMEOUT: number;
2122

2223
resolveConfig(false).then(config => MIDDLEWARE_TIMEOUT = config.MIDDLEWARE_TIMEOUT || 10000);
2324

2425
export class AxonRouteHandler<P = {}> {
25-
public _controller: FuncController<P>;
26+
public _controller: FuncController<P> | ClassController<any, any>;
2627
public _middlewares: MiddlewareStorage[];
2728

28-
constructor(controller: FuncController<P>) {
29+
constructor(controller: FuncController<P> | ClassController<any, any>) {
2930
this._controller = controller;
3031
this._middlewares = [];
3132
}
@@ -41,6 +42,7 @@ export class AxonRouteHandler<P = {}> {
4142
}
4243
}
4344

45+
4446
class AxonRouter {
4547
private routes: HttpMethods;
4648
public prefix: string | undefined;
@@ -86,11 +88,20 @@ class AxonRouter {
8688
* }
8789
* ])
8890
*/
89-
public get<Path extends string>(path: Path, controller: FuncController<RouteParams<Path>>, validation?: ValidationObj[]) {
91+
public get<Path extends string, C extends BaseController, M extends keyof C>(
92+
path: Path,
93+
controller: (
94+
FuncController<RouteParams<Path>>
95+
| ClassController<C, M>),
96+
validation?: ValidationObj[]
97+
) {
98+
9099
if (this.routes.GET[path]) {
91100
duplicateError(path, "GET")
92101
}
93102

103+
this.validateController(controller);
104+
94105
path = this.handleRoutePrefix(path) as Path;
95106

96107
const handler = new AxonRouteHandler(controller);
@@ -137,11 +148,20 @@ class AxonRouter {
137148
* }
138149
* ])
139150
*/
140-
public post<Path extends string>(path: Path, controller: FuncController<RouteParams<Path>>, validation?: ValidationObj[]) {
151+
public post<Path extends string, C extends BaseController, M extends keyof C>(
152+
path: Path,
153+
controller: (
154+
FuncController<RouteParams<Path>>
155+
| ClassController<C, M>),
156+
validation?: ValidationObj[]
157+
) {
158+
141159
if (this.routes.POST[path]) {
142160
duplicateError(path, "POST")
143161
}
144162

163+
this.validateController(controller);
164+
145165
path = this.handleRoutePrefix(path) as Path;
146166

147167
const handler = new AxonRouteHandler(controller);
@@ -183,11 +203,20 @@ class AxonRouter {
183203
* }
184204
* ])
185205
*/
186-
public put<Path extends string>(path: Path, controller: FuncController<RouteParams<Path>>, validation?: ValidationObj[]) {
206+
public put<Path extends string, C extends BaseController, M extends keyof C>(
207+
path: Path,
208+
controller: (
209+
FuncController<RouteParams<Path>>
210+
| ClassController<C, M>),
211+
validation?: ValidationObj[]
212+
) {
213+
187214
if (this.routes.PUT[path]) {
188215
duplicateError(path, "PUT")
189216
}
190217

218+
this.validateController(controller);
219+
191220
path = this.handleRoutePrefix(path) as Path;
192221

193222
const handler = new AxonRouteHandler(controller);
@@ -233,11 +262,20 @@ class AxonRouter {
233262
* }
234263
* ])
235264
*/
236-
public patch<Path extends string>(path: Path, controller: FuncController<RouteParams<Path>>, validation?: ValidationObj[]) {
265+
public patch<Path extends string, C extends BaseController, M extends keyof C>(
266+
path: Path,
267+
controller: (
268+
FuncController<RouteParams<Path>>
269+
| ClassController<C, M>),
270+
validation?: ValidationObj[]
271+
) {
272+
237273
if (this.routes.PATCH[path]) {
238274
duplicateError(path, "PATCH")
239275
}
240276

277+
this.validateController(controller);
278+
241279
path = this.handleRoutePrefix(path) as Path;
242280

243281
const handler = new AxonRouteHandler(controller);
@@ -280,11 +318,20 @@ class AxonRouter {
280318
* }
281319
* ])
282320
*/
283-
public delete<Path extends string>(path: Path, controller: FuncController<RouteParams<Path>>, validation?: ValidationObj[]) {
321+
public delete<Path extends string, C extends BaseController, M extends keyof C>(
322+
path: Path,
323+
controller: (
324+
FuncController<RouteParams<Path>>
325+
| ClassController<C, M>),
326+
validation?: ValidationObj[]
327+
) {
328+
284329
if (this.routes.DELETE[path]) {
285330
duplicateError(path, "DELETE")
286331
}
287332

333+
this.validateController(controller);
334+
288335
path = this.handleRoutePrefix(path) as Path;
289336

290337
const handler = new AxonRouteHandler(controller);
@@ -316,11 +363,20 @@ class AxonRouter {
316363
* res.send("Hello World");
317364
* });
318365
*/
319-
public options<Path extends string>(path: Path, controller: FuncController<RouteParams<Path>>, validation?: ValidationObj[]) {
366+
public options<Path extends string, C extends BaseController, M extends keyof C>(
367+
path: Path,
368+
controller: (
369+
FuncController<RouteParams<Path>>
370+
| ClassController<C, M>),
371+
validation?: ValidationObj[]
372+
) {
373+
320374
if (this.routes.OPTIONS[path]) {
321375
duplicateError(path, "OPTIONS")
322376
}
323377

378+
this.validateController(controller);
379+
324380
path = this.handleRoutePrefix(path) as Path;
325381

326382
const handler = new AxonRouteHandler(controller);
@@ -363,16 +419,16 @@ class AxonRouter {
363419
let i = 0;
364420
while (i < path.length) {
365421
if (path[i] === '{') {
366-
422+
367423
const endBrace = path.indexOf('}', i);
368424
if (endBrace === -1) {
369425
throw new Error("Unclosed parameter brace in route: " + path);
370426
}
371-
427+
372428
const paramName = path.slice(i + 1, endBrace);
373429
paramNames.push(paramName);
374430
i = endBrace + 1;
375-
431+
376432
if (i < path.length && path[i] === '(') {
377433
const endParen = path.indexOf(')', i);
378434
if (endParen === -1) {
@@ -382,11 +438,11 @@ class AxonRouter {
382438
regexString += `(${customRegex})`;
383439
i = endParen + 1;
384440
} else {
385-
441+
386442
regexString += '([^/]+)';
387443
}
388444
} else {
389-
445+
390446
const nextBrace = path.indexOf('{', i);
391447
const literal = nextBrace === -1 ? path.slice(i) : path.slice(i, nextBrace);
392448
regexString += this.escapeRegExp(literal);
@@ -398,7 +454,7 @@ class AxonRouter {
398454
}
399455

400456
private escapeRegExp(text: string): string {
401-
457+
402458
return text.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1');
403459
}
404460

@@ -425,6 +481,22 @@ class AxonRouter {
425481
handler.middleware(AxonValidator.validate(validator.schema, validator.options, validator.target), undefined, true);
426482
}
427483
}
484+
485+
/**
486+
* Check controller type and if it was class controller, it must be extends from BaseController.
487+
* @param controller
488+
*/
489+
private validateController(controller: FuncController<any> | ClassController<any, any>) {
490+
if (Array.isArray(controller)) {
491+
const [ControllerClass, method] = controller;
492+
493+
if (!(ControllerClass?.prototype instanceof BaseController)) {
494+
throw new Error(`Controller class must extends from BaseController`, {
495+
cause: ControllerClass
496+
});
497+
}
498+
}
499+
}
428500
}
429501

430502
export default AxonRouter;

0 commit comments

Comments
 (0)