cantian-rest 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BaseController.d.ts +27 -0
- package/dist/BaseController.js +59 -0
- package/dist/BaseController.js.map +1 -0
- package/dist/RestError.d.ts +16 -0
- package/dist/RestError.js +29 -0
- package/dist/RestError.js.map +1 -0
- package/dist/app.d.ts +1 -0
- package/dist/app.js +3 -0
- package/dist/app.js.map +1 -0
- package/dist/bin/server.d.ts +1 -0
- package/dist/bin/server.js +21 -0
- package/dist/bin/server.js.map +1 -0
- package/dist/handlers.d.ts +12 -0
- package/dist/handlers.js +113 -0
- package/dist/handlers.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/test.d.ts +1 -0
- package/dist/test.js +2 -0
- package/dist/test.js.map +1 -0
- package/package.json +26 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import Ajv, { ValidateFunction } from 'ajv';
|
|
2
|
+
import { JSONSchema } from 'json-schema-to-ts';
|
|
3
|
+
import { Auth } from './type.js';
|
|
4
|
+
export declare class BaseController {
|
|
5
|
+
static successStatusCode: number;
|
|
6
|
+
static dataAjv: Ajv.Ajv;
|
|
7
|
+
static validateData: ValidateFunction | undefined;
|
|
8
|
+
static resultAjv: Ajv.Ajv;
|
|
9
|
+
static validateResult: ValidateFunction | undefined;
|
|
10
|
+
static inited: boolean;
|
|
11
|
+
static isPublic: boolean;
|
|
12
|
+
['constructor']: typeof BaseController;
|
|
13
|
+
data?: any;
|
|
14
|
+
auth?: Auth;
|
|
15
|
+
pathParams?: Record<string, string>;
|
|
16
|
+
static init(): void;
|
|
17
|
+
constructor(event: {
|
|
18
|
+
data?: any;
|
|
19
|
+
auth?: Auth;
|
|
20
|
+
pathParams?: Record<string, string>;
|
|
21
|
+
});
|
|
22
|
+
static dataSchema(): JSONSchema | undefined;
|
|
23
|
+
static resultSchema(): JSONSchema | undefined;
|
|
24
|
+
static getInvalidProperty(validateFunction: ValidateFunction): string;
|
|
25
|
+
execute(): Promise<any>;
|
|
26
|
+
run(): Promise<any>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import Ajv from 'ajv';
|
|
2
|
+
import { RestError } from './RestError.js';
|
|
3
|
+
export class BaseController {
|
|
4
|
+
static successStatusCode = 200;
|
|
5
|
+
static dataAjv = new Ajv.default({ removeAdditional: true, useDefaults: true });
|
|
6
|
+
static validateData;
|
|
7
|
+
static resultAjv = new Ajv.default({ removeAdditional: true, useDefaults: true });
|
|
8
|
+
static validateResult;
|
|
9
|
+
static inited;
|
|
10
|
+
static isPublic;
|
|
11
|
+
data;
|
|
12
|
+
auth;
|
|
13
|
+
pathParams;
|
|
14
|
+
static init() {
|
|
15
|
+
const dataSchema = this.dataSchema();
|
|
16
|
+
this.validateData = dataSchema ? this.dataAjv.compile(dataSchema) : undefined;
|
|
17
|
+
const resultSchema = this.resultSchema();
|
|
18
|
+
this.validateResult = resultSchema ? this.resultAjv.compile(resultSchema) : undefined;
|
|
19
|
+
}
|
|
20
|
+
constructor(event) {
|
|
21
|
+
const constructor = this.constructor;
|
|
22
|
+
this.data = event.data;
|
|
23
|
+
this.auth = event.auth;
|
|
24
|
+
this.pathParams = event.pathParams;
|
|
25
|
+
if (!constructor.inited) {
|
|
26
|
+
constructor.init();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
static dataSchema() {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
static resultSchema() {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
static getInvalidProperty(validateFunction) {
|
|
36
|
+
return (validateFunction.errors?.[0]?.instancePath?.slice(1) ||
|
|
37
|
+
validateFunction.errors?.[0]?.params?.additionalProperty ||
|
|
38
|
+
validateFunction.errors?.[0]?.params?.missingProperty);
|
|
39
|
+
}
|
|
40
|
+
async execute() {
|
|
41
|
+
const constructor = this.constructor;
|
|
42
|
+
// Validate data
|
|
43
|
+
if (constructor.validateData && !constructor.validateData(this.data)) {
|
|
44
|
+
throw RestError.badRequest('Invalid request body.', constructor.validateData.errors?.[0]);
|
|
45
|
+
}
|
|
46
|
+
// Run and validate result
|
|
47
|
+
const result = await this.run();
|
|
48
|
+
if (constructor.validateResult) {
|
|
49
|
+
if (!constructor.validateResult(result)) {
|
|
50
|
+
throw RestError.internal('Unexpected result.', constructor.validateResult.errors?.[0]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
async run() {
|
|
56
|
+
throw RestError.internal('Method not implemented.');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=BaseController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseController.js","sourceRoot":"","sources":["../src/BaseController.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ErrorResponseBody = {
|
|
2
|
+
errorMessage: string;
|
|
3
|
+
errorData?: any;
|
|
4
|
+
};
|
|
5
|
+
export declare class RestError {
|
|
6
|
+
statusCode: number;
|
|
7
|
+
errorMessage: string;
|
|
8
|
+
errorData?: any | undefined;
|
|
9
|
+
constructor(statusCode: number, errorMessage: string, errorData?: any | undefined);
|
|
10
|
+
static internal(errorMessage?: string, errorData?: ErrorResponseBody['errorData']): RestError;
|
|
11
|
+
static notFound(errorMessage?: string, errorData?: ErrorResponseBody['errorData']): RestError;
|
|
12
|
+
static badRequest(errorMessage?: string, errorData?: ErrorResponseBody['errorData']): RestError;
|
|
13
|
+
static forbidden(errorMessage?: string, errorData?: ErrorResponseBody['errorData']): RestError;
|
|
14
|
+
static unauthorized(errorMessage?: string, errorData?: ErrorResponseBody['errorData']): RestError;
|
|
15
|
+
static conflict(errorMessage?: string, errorData?: ErrorResponseBody['errorData']): RestError;
|
|
16
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export class RestError {
|
|
2
|
+
statusCode;
|
|
3
|
+
errorMessage;
|
|
4
|
+
errorData;
|
|
5
|
+
constructor(statusCode, errorMessage, errorData) {
|
|
6
|
+
this.statusCode = statusCode;
|
|
7
|
+
this.errorMessage = errorMessage;
|
|
8
|
+
this.errorData = errorData;
|
|
9
|
+
}
|
|
10
|
+
static internal(errorMessage, errorData) {
|
|
11
|
+
return new RestError(500, errorMessage || 'Internal server error.', errorData);
|
|
12
|
+
}
|
|
13
|
+
static notFound(errorMessage, errorData) {
|
|
14
|
+
return new RestError(404, errorMessage || 'Resource not found.', errorData);
|
|
15
|
+
}
|
|
16
|
+
static badRequest(errorMessage, errorData) {
|
|
17
|
+
return new RestError(400, errorMessage || 'Bad request.', errorData);
|
|
18
|
+
}
|
|
19
|
+
static forbidden(errorMessage, errorData) {
|
|
20
|
+
return new RestError(403, errorMessage || 'Forbidden.', errorData);
|
|
21
|
+
}
|
|
22
|
+
static unauthorized(errorMessage, errorData) {
|
|
23
|
+
return new RestError(401, errorMessage || 'Unauthorized.', errorData);
|
|
24
|
+
}
|
|
25
|
+
static conflict(errorMessage, errorData) {
|
|
26
|
+
return new RestError(409, errorMessage || 'Conflict.', errorData);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=RestError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RestError.js","sourceRoot":"","sources":["../src/RestError.ts"],"names":[],"mappings":"AAKA,MAAM,OAAO,SAAS;IACD;IAA2B;IAA6B;IAA3E,YAAmB,UAAkB,EAAS,YAAoB,EAAS,SAAe;QAAvE,eAAU,GAAV,UAAU,CAAQ;QAAS,iBAAY,GAAZ,YAAY,CAAQ;QAAS,cAAS,GAAT,SAAS,CAAM;IAAG,CAAC;IAE9F,MAAM,CAAC,QAAQ,CAAC,YAAqB,EAAE,SAA0C;QAC/E,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,YAAY,IAAI,wBAAwB,EAAE,SAAS,CAAC,CAAC;IACjF,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,YAAqB,EAAE,SAA0C;QAC/E,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,YAAY,IAAI,qBAAqB,EAAE,SAAS,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,YAAqB,EAAE,SAA0C;QACjF,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,YAAY,IAAI,cAAc,EAAE,SAAS,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,CAAC,SAAS,CAAC,YAAqB,EAAE,SAA0C;QAChF,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,YAAY,IAAI,YAAY,EAAE,SAAS,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,YAAqB,EAAE,SAA0C;QACnF,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,YAAY,IAAI,eAAe,EAAE,SAAS,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,YAAqB,EAAE,SAA0C;QAC/E,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,YAAY,IAAI,WAAW,EAAE,SAAS,CAAC,CAAC;IACpE,CAAC;CACF"}
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const app: import("express-serve-static-core").Express;
|
package/dist/app.js
ADDED
package/dist/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,MAAM,CAAC,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { app } from '../app.js';
|
|
3
|
+
import { createAuthHandler, createControllerRouter } from '../handlers.js';
|
|
4
|
+
const { JWTS, SCOPE, PORT = 3001 } = process.env;
|
|
5
|
+
if (fs.existsSync('dist/controllers')) {
|
|
6
|
+
const controllerDir = process.cwd() + '/dist/controllers/';
|
|
7
|
+
const router = await createControllerRouter({
|
|
8
|
+
controllerDir,
|
|
9
|
+
auth: JWTS
|
|
10
|
+
? createAuthHandler({
|
|
11
|
+
jwts: JWTS,
|
|
12
|
+
scope: SCOPE,
|
|
13
|
+
})
|
|
14
|
+
: undefined,
|
|
15
|
+
});
|
|
16
|
+
app.use('/rest', router);
|
|
17
|
+
}
|
|
18
|
+
app.listen(PORT, () => {
|
|
19
|
+
console.info(`Server is ready on port ${PORT}.`);
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/bin/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE3E,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;AAEjD,IAAI,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;IACtC,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,oBAAoB,CAAC;IAC3D,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC;QAC1C,aAAa;QACb,IAAI,EAAE,IAAI;YACR,CAAC,CAAC,iBAAiB,CAAC;gBAChB,IAAI,EAAE,IAAI;gBACV,KAAK,EAAE,KAAK;aACb,CAAC;YACJ,CAAC,CAAC,SAAS;KACd,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IACpB,OAAO,CAAC,IAAI,CAAC,2BAA2B,IAAI,GAAG,CAAC,CAAC;AACnD,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Request, RequestHandler, Response } from 'express';
|
|
2
|
+
import { BaseController } from './BaseController.js';
|
|
3
|
+
export declare const createAuthHandler: (options: {
|
|
4
|
+
jwts: string;
|
|
5
|
+
scope?: string;
|
|
6
|
+
}) => (req: any, res: any, next: any) => Promise<any>;
|
|
7
|
+
export declare const createBizHandler: (c: typeof BaseController) => (req: Request, res: Response, next: any) => Promise<void>;
|
|
8
|
+
export declare const createControllerRouter: (options: {
|
|
9
|
+
controllerDir: string;
|
|
10
|
+
auth?: RequestHandler;
|
|
11
|
+
}) => Promise<import("express-serve-static-core").Router>;
|
|
12
|
+
export declare const catchError: (err: any, req: any, res: Response, next: any) => void;
|
package/dist/handlers.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import express, { json } from 'express';
|
|
2
|
+
import { createLocalJWKSet, createRemoteJWKSet, jwtVerify } from 'jose';
|
|
3
|
+
import { glob } from 'node:fs/promises';
|
|
4
|
+
import { RestError } from './RestError.js';
|
|
5
|
+
export const createAuthHandler = (options) => async (req, res, next) => {
|
|
6
|
+
const authorization = req.headers['authorization'];
|
|
7
|
+
if (!authorization) {
|
|
8
|
+
throw RestError.unauthorized('Authorization header is required.');
|
|
9
|
+
}
|
|
10
|
+
const [tokenType, token] = authorization.split(' ');
|
|
11
|
+
if (tokenType !== 'Bearer') {
|
|
12
|
+
throw RestError.unauthorized('Authorization token type is unsupported.');
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
let jwts;
|
|
16
|
+
if (options.jwts.startsWith('http')) {
|
|
17
|
+
jwts = createRemoteJWKSet(new URL(options.jwts));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
jwts = createLocalJWKSet(JSON.parse(jwts));
|
|
21
|
+
}
|
|
22
|
+
const { payload } = await jwtVerify(token, jwts);
|
|
23
|
+
if (options.scope) {
|
|
24
|
+
const tokenScopes = payload.scope?.split(' ');
|
|
25
|
+
if (!tokenScopes?.includes(options.scope)) {
|
|
26
|
+
throw RestError.forbidden();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
req.auth = {
|
|
30
|
+
sub: payload.sub,
|
|
31
|
+
name: payload.name,
|
|
32
|
+
aud: payload.aud,
|
|
33
|
+
};
|
|
34
|
+
return next();
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
throw RestError.unauthorized();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
export const createBizHandler = (c) => async (req, res, next) => {
|
|
41
|
+
const controller = new c({
|
|
42
|
+
data: req.body,
|
|
43
|
+
auth: req.auth,
|
|
44
|
+
pathParams: req.params,
|
|
45
|
+
});
|
|
46
|
+
const result = await controller.execute();
|
|
47
|
+
res.status(c.successStatusCode).json(result);
|
|
48
|
+
next();
|
|
49
|
+
};
|
|
50
|
+
export const createControllerRouter = async (options) => {
|
|
51
|
+
const { controllerDir, auth } = options;
|
|
52
|
+
const allowedMethods = ['get', 'post', 'patch'];
|
|
53
|
+
const controllerFiles = glob('**/*.js', { cwd: controllerDir });
|
|
54
|
+
const router = express.Router();
|
|
55
|
+
router.use(json());
|
|
56
|
+
router.use((req, res, next) => {
|
|
57
|
+
console.log(JSON.stringify({
|
|
58
|
+
event: 'REQUEST',
|
|
59
|
+
time: new Date().toISOString(),
|
|
60
|
+
method: req.method,
|
|
61
|
+
path: req.path,
|
|
62
|
+
data: req.body,
|
|
63
|
+
}));
|
|
64
|
+
next();
|
|
65
|
+
});
|
|
66
|
+
for await (const controllerFile of controllerFiles) {
|
|
67
|
+
const parts = controllerFile.split('/');
|
|
68
|
+
const method = parts.pop()?.replace('.js', '').toLowerCase();
|
|
69
|
+
if (!allowedMethods.includes(method)) {
|
|
70
|
+
throw new Error(`The method is invalid for the file ${controllerFile}.`);
|
|
71
|
+
}
|
|
72
|
+
const urlPath = '/' + parts.join('/');
|
|
73
|
+
const { default: c } = await import(`${controllerDir}/${controllerFile}`);
|
|
74
|
+
if (!c.isPublic) {
|
|
75
|
+
if (!auth) {
|
|
76
|
+
throw new Error(`Auth option is required since the controller ${urlPath}/${method} is private.`);
|
|
77
|
+
}
|
|
78
|
+
router[method](urlPath, auth);
|
|
79
|
+
}
|
|
80
|
+
router[method](urlPath, createBizHandler(c));
|
|
81
|
+
console.log(`Route: ${method.toUpperCase()} ${urlPath}`);
|
|
82
|
+
}
|
|
83
|
+
router.use(catchError);
|
|
84
|
+
router.use((req, res, next) => {
|
|
85
|
+
console.log(JSON.stringify({
|
|
86
|
+
event: 'RESPONSE',
|
|
87
|
+
time: new Date().toISOString(),
|
|
88
|
+
statusCode: res.statusCode,
|
|
89
|
+
}));
|
|
90
|
+
next();
|
|
91
|
+
});
|
|
92
|
+
return router;
|
|
93
|
+
};
|
|
94
|
+
export const catchError = (err, req, res, next) => {
|
|
95
|
+
if (err instanceof RestError) {
|
|
96
|
+
res.status(err.statusCode).json({
|
|
97
|
+
error: {
|
|
98
|
+
data: err.errorData,
|
|
99
|
+
message: err.errorMessage,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
console.error(err);
|
|
105
|
+
res.status(500).json({
|
|
106
|
+
error: {
|
|
107
|
+
message: 'Internal error.',
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
next();
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
package/dist/test.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/test.js
ADDED
package/dist/test.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../src/test.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cantian-rest",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"bin": {
|
|
12
|
+
"cantian-rest-server": "./dist/bin/server.js"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"prepublishOnly": "rm -rf dist && tsc"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/express": "^5.0.1",
|
|
19
|
+
"json-schema-to-ts": "^3.1.1"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"ajv": "^8.17.1",
|
|
23
|
+
"express": "^5.1.0",
|
|
24
|
+
"jose": "^6.0.11"
|
|
25
|
+
}
|
|
26
|
+
}
|