Move Express middleware to separate modules - node.js

I have lots of app.use(...) in my express app, and they get messy and complex and there's config all over the place. So I want to move them to separate modules so they're easier to test.
So I have this Middleware.ts base class for my middleware wrappers:
export default abstract class Middleware {
public run(): express.RequestHandler {
try {
return this.runImpl;
}
catch (err) {
log("Failed to init middleware " + err);
throw err;
}
}
public abstract runImpl(): express.RequestHandler;
}
And a subclass, e.g. StaticMiddleware.ts for serving static files:
export class StaticMiddleware extends Middleware {
public runImp(): express.RequestHandler {
// this is a simple example, but most middleware are more
// complicated, but everything is encapsulated here
return express.static("path");
}
}
export default new StaticMiddleware().run;
Finally the app.ts express app itself, which is very clean:
import staticMiddleware from "./StaticMiddleware";
import fooMiddleware from "./FooMiddleware";
import barMiddleware from "./BarMiddleware";
app.use(staticMiddleware());
app.use(fooMiddleware());
app.use(barMiddleware());
But I get an error at runtime:
TypeError: app.use() requires a middleware function
Note it's possible to change the method signatures above, so I can use this form:
app.use(staticMiddleware);
But that is surprising to a maintainer, and so liable to break. I want the normal signature:
app.use(staticMiddleware());

Related

TypeScript Not Recognising Exported Firebase Cloud Functions

Problem Intro
I have over a hundred Firebase Cloud Functions, and to keep the code organised, I split them into separate files per function (e.g., userFunctions, adminFunctions, authFunctions, ...) as per the instructions in the official Firebase thread.
In my index.ts I import all the different function files as:
import * as adminFunctions from './modules/adminFunctions';
import * as userFunctions from './modules/userFunctions';
...
exports.adminFunctions = adminFunctions;
exports.userFunctions = userFunctions;
...
In my userFunctions.ts file, I would declare the individual functions, some of which would call additional reusable functions from authFunctions.ts
userFunctions.ts
import { https } from 'firebase-functions';
import { performAppCheckAuthentication } from './supportingFunctions/authFunctions';
exports.deleteExpiredOrganisationMembershipInvite = https.onCall(async (data, context) => {
// Perform AppCheck authentication
performAppCheckAuthentication(data, context)
// More code
...
})
The cross-referenced authFunctions.ts would look like this:
exports.performAppCheckAuthentication = function (
data: { [key: string]: any },
context: CallableContext
) {
return true; // There would be actual logic here in the real code
}
Exact Issue
When I have TypeScript try to compile this code, it gives me the following error in the userFunctions.ts file in the import statement:
Module '"./supportingFunctions/authFunctions"' has no exported member
'performAppCheckAuthentication'.
How can I keep my code split into different files to retain maintainability, but also get around this issue of not being able to import the functions?
You probably want to use the export statement instead of the exports global:
export function performAppCheckAuthentication(
data: { [key: string]: any },
context: CallableContext
) {
return true; // There would be actual logic here in the real code
}
export const deleteExpiredOrganisationMembershipInvite = https.onCall(async (data, context) => {
// Perform AppCheck authentication
performAppCheckAuthentication(data, context)
// More code
...
})
Docs

How to use Winston Logger in NestJS separate module that doesn't use Classes

I've tried a few different ways of doing this.
I can't set Winston as the default logger for NestJS at the moment because it complains about "getTimestamp" function not being in the instance.
So - for controllers in NestJS - I have used dependency injection - which works fine for the api ( REST endpoints ).
The problem is that I have moved away from OOP - so all of my libraries are written in typescript as functions. Not pure functions but better than an OOP approach ( many less bugs! )
My question is - how do I get access to the main winston logger within my libraries that don't have classes.
I am using the library nest-winston.
Have you tried this?
create the logger outside of the application lifecycle, using the createLogger function, and pass it to NestFactory.create (nest-winston docs)
You can have a separate file that creates the logging instance, then import that into your modules/libraries as well as import it into your main.ts
// src/logger/index.ts
import { WinstonModule } from 'nest-winston';
export const myLogger = WinstonModule.createLogger({
// options (same as WinstonModule.forRoot() options)
})
// src/myLib/index.ts
import { myLogger } from '#/logger' // I like using aliases
export const myLib = () => {
// ...
myLogger.log('Yay')
}
// src/main.ts
import { myLogger } from '#/logger'
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
logger: myLogger
});
}
bootstrap();

Import Module in ES6 Class Function

I have migrated my project to ESM and thus using .mjs in all my files in nodejs.
Previously in CommonJs, I could require a file right in the middle of a ES6 class function in order to load it only when needed.
module.exports = class Core{
constructor() {
this.init = this._init.bind(this)
return this.init()
}
async _init(){
const module = require('module')
//use required file/module here
}
}
But now when using Michael Jackson Scripts a.k.a .mjs, I cannot import a file on demand:
import Koa from 'koa'
export default = class Core{
constructor() {
this.init = this._init.bind(this)
return this.init()
}
async _init(){
import module from 'module'
//use imported file/module here
}
}
My app has many files/modules that are not consumed immediately, and can more can always be added in future, thus hardcoding the imports at the begining of the file is not an option.
Is there a way to import the files dynamically on demand when needed?
With a little modification from this answer, I managed to get it working via:
import Koa from 'koa'
export default = class Core{
constructor() {
this.init = this._init.bind(this)
return this.init()
}
async _init(){
const router = await import('./Router')
//use imported file/module here
}
}
Or you can use a promise if you are into that:
import('./router')
.then(something => {
//use imported module here
});
This suits me for now until the spec if finalised and shipped

Access extended class' properties and methods with TypeScript decorators

I'm working on an experimental refactoring of my express app and chose to go with TypeScript as I prefer strong typing with any language. I saw the potential of using TypeScript's decorators as a powerful method to build a well-structured project as DRY as possible.
I'm having issues in accessing a property from a class that is extended by a class where I have the decorator set up.
example:
class BaseRouter {
app: express.Application = express;
// some other common stuff
}
function PostMethod(route: string = '/') {
return (target: BaseRouter, key: string, descriptor: PropertyDescriptor): void {
// This is where things don't work out
// descriptor.value correctly returns the RequestHandler which I can attach to express
// target.app is undefined
target.app.post(route, descriptor.value);
}
}
router.ts
#ResourceRouter() // <= this is optional, can I access all decorators inside the class from this decorator? That would also lead me to a solution
export class BlogRouter extends BaseRouter {
#GetMethod()
index(req, res) {
// req.send(...); return posts
}
#GetMethod('/:modelId')
show(req, res, next) {
// find req.params.modelId
}
#PostMethod()
createPost() {}
#DeleteMethod()
deletePost() {}
#UpdateMethod()
updatePost() {}
}
I know this is not perfect I'm just experimenting with decorators at the moment as I have successfully used them in other scenarios that works really well. Note that this is not in any way Angular 2+ related.

Using dart2js output with Cloud Code by Parse.com

First, I transpose the javascript example into a dart one.
JS
Parse.Cloud.define('hello', function(request, response) {
response.success('Hello world');
});
DART
import 'dart:js' show allowInterop;
import 'package:js/js.dart' show JS;
#JS('Parse.Cloud.define')
external void define(String name, Function func);
void main() {
define('hello', allowInterop((req, res) {
res.success('Yeah!');
}));
}
Then I compile it using dart2js (with csp or not).
Finally I run parse deploy and I get
ReferenceError: self is not defined
at <error: TypeError: Object #<error> has no method '__lookupGetter__'>
at main.js:2539:9
at init.currentScript (main.js:2519:7)
at main.js:2534:5
at main.js:2542:3
and now, here I am...
How I could get it work on parse.com which is a nodejs env I presume.
self is effectively not defined in the environement provided by parse.com, so I defined self such as var self = this; in the dart2js output.
I get a new error, about success$1 is not defined. Well, that's true, my code is still incomplet...
Dart code should like this:
import 'dart:js' show allowInterop;
import 'package:js/js.dart' show JS, anonymous;
#JS('Parse.Cloud.define')
external void define(String name, Function func);
#JS()
#anonymous
class HttpResponse {
external void success(String msg);
external void error(String msg);
}
void main() {
define('hello', allowInterop((req, HttpResponse res) {
res.success('Yeah!');
}));
}
Now, everything work. I can enjoy my sunday.

Resources