@opra/nestjs-http
Version:
Opra NestJS Http Module
168 lines (167 loc) • 7.91 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpraHttpNestjsAdapter = void 0;
const tslib_1 = require("tslib");
const node_path_1 = tslib_1.__importDefault(require("node:path"));
const objects_1 = require("@jsopen/objects");
const common_1 = require("@nestjs/common");
const common_2 = require("@opra/common");
const http_1 = require("@opra/http");
const nestjs_1 = require("@opra/nestjs");
const ts_gems_1 = require("ts-gems");
class OpraHttpNestjsAdapter extends http_1.HttpAdapter {
constructor(options) {
super(options);
this.nestControllers = [];
this._addRootController(options.schemaIsPublic);
if (options.controllers) {
for (const c of options.controllers) {
this._addToNestControllers(c, this.basePath, []);
}
}
}
async close() {
//
}
_addRootController(isPublic) {
const _this = this;
let RootController = class RootController {
schema(_req, next) {
_this.handler.sendDocumentSchema(_req.opraContext).catch(() => next());
}
};
tslib_1.__decorate([
(0, common_1.Get)('/\\$schema'),
tslib_1.__param(0, (0, common_1.Req)()),
tslib_1.__param(1, (0, common_1.Next)()),
tslib_1.__metadata("design:type", Function),
tslib_1.__metadata("design:paramtypes", [Object, Function]),
tslib_1.__metadata("design:returntype", void 0)
], RootController.prototype, "schema", null);
RootController = tslib_1.__decorate([
(0, common_1.Controller)({
path: this.basePath,
})
], RootController);
if (isPublic) {
(0, nestjs_1.Public)()(RootController.prototype, 'schema', Object.getOwnPropertyDescriptor(RootController.prototype, 'schema'));
}
this.nestControllers.push(RootController);
}
_addToNestControllers(sourceClass, currentPath, parentTree) {
const metadata = Reflect.getMetadata(common_2.HTTP_CONTROLLER_METADATA, sourceClass);
if (!metadata)
return;
/** Create a new controller class */
const newClass = {
[sourceClass.name]: class extends sourceClass {
},
}[sourceClass.name];
/** Copy metadata keys from source class to new one */
nestjs_1.OpraNestUtils.copyDecoratorMetadata(newClass, ...parentTree);
(0, common_1.Controller)()(newClass);
const newPath = metadata.path
? node_path_1.default.join(currentPath, metadata.path)
: currentPath;
const adapter = this;
// adapter.logger =
/** Disable default error handler. Errors will be handled by OpraExceptionFilter */
adapter.handler.onError = (context, error) => {
throw error;
};
this.nestControllers.push(newClass);
let metadataKeys;
if (metadata.operations) {
for (const [k, v] of Object.entries(metadata.operations)) {
const operationHandler = sourceClass.prototype[k];
Object.defineProperty(newClass.prototype, k, {
writable: true,
/** NestJS handler method */
async value(_req, _res) {
_res.statusCode = 200;
const api = adapter.document.api;
const controller = api.findController(sourceClass);
const operation = controller?.operations.get(k);
const context = (0, ts_gems_1.asMutable)(_req.opraContext);
if (!(context && operation && typeof operationHandler === 'function')) {
throw new common_2.NotFoundError({
message: `No endpoint found for [${_req.method}]${_req.baseUrl}`,
details: {
path: _req.baseUrl,
method: _req.method,
},
});
}
/** Configure the HttpContext */
context.operation = operation;
context.controller = operation.owner;
context.controllerInstance = this;
context.operationHandler = operationHandler;
/** Handle request */
await adapter.handler.handleRequest(context);
},
});
/** Copy metadata keys from source function to new one */
metadataKeys = Reflect.getOwnMetadataKeys(operationHandler);
const newFn = newClass.prototype[k];
for (const key of metadataKeys) {
const m = Reflect.getMetadata(key, operationHandler);
Reflect.defineMetadata(key, m, newFn);
}
(0, common_1.Req)()(newClass.prototype, k, 0);
(0, common_1.Res)()(newClass.prototype, k, 1);
const descriptor = Object.getOwnPropertyDescriptor(newClass.prototype, k);
const operationPath = v.mergePath
? newPath + (v.path || '')
: node_path_1.default.posix.join(newPath, v.path || '');
switch (v.method || 'GET') {
case 'DELETE':
/** Call @Delete decorator over new property */
(0, common_1.Delete)(operationPath)(newClass.prototype, k, descriptor);
break;
case 'GET':
/** Call @Get decorator over new property */
(0, common_1.Get)(operationPath)(newClass.prototype, k, descriptor);
break;
case 'HEAD':
/** Call @Head decorator over new property */
(0, common_1.Head)(operationPath)(newClass.prototype, k, descriptor);
break;
case 'OPTIONS':
/** Call @Options decorator over new property */
(0, common_1.Options)(operationPath)(newClass.prototype, k, descriptor);
break;
case 'PATCH':
/** Call @Patch decorator over new property */
(0, common_1.Patch)(operationPath)(newClass.prototype, k, descriptor);
break;
case 'POST':
/** Call @Post decorator over new property */
(0, common_1.Post)(operationPath)(newClass.prototype, k, descriptor);
break;
case 'PUT':
/** Call @Put decorator over new property */
(0, common_1.Put)(operationPath)(newClass.prototype, k, descriptor);
break;
case 'SEARCH':
/** Call @Search decorator over new property */
(0, common_1.Search)(operationPath)(newClass.prototype, k, descriptor);
break;
default:
break;
}
}
}
if (metadata.controllers) {
for (const child of metadata.controllers) {
if (!(0, objects_1.isConstructor)(child))
throw new TypeError('Controllers should be injectable a class');
this._addToNestControllers(child, newPath, [
...parentTree,
sourceClass,
]);
}
}
}
}
exports.OpraHttpNestjsAdapter = OpraHttpNestjsAdapter;