Repository: MaskingTechnology/jitar (ts)

Issue:
Reverse the execution order of the registered middleware
Currently the registered middleware is executed in reverse order. This is a bit confusing, so we need to reverse the execution order.

Pull request description:
feat(runtime): Reversed middleware execution order
Fixes #290 

Changes proposed in this pull request:
- Reversed the execution order of the middleware (first added gets executed first)

@MaskingTechnology/jitar


Patch:
diff --git a/packages/runtime/src/services/ProcedureRuntime.ts b/packages/runtime/src/services/ProcedureRuntime.ts
index 5cbe0ea..dc0b7b9 100644
--- a/packages/runtime/src/services/ProcedureRuntime.ts
+++ b/packages/runtime/src/services/ProcedureRuntime.ts
@@ -15,7 +15,7 @@ export default abstract class ProcedureRuntime extends Runtime implements Runner
     {
         super(url);
 
-        this.addMiddleware(new ProcedureRunner(this));
+        this.#middlewares.push(new ProcedureRunner(this));
     }
 
     abstract getProcedureNames(): string[];
@@ -26,7 +26,12 @@ export default abstract class ProcedureRuntime extends Runtime implements Runner
 
     addMiddleware(middleware: Middleware)
     {
-        this.#middlewares.push(middleware);
+        // We want to add the middleware before the ProcedureRunner because
+        // it is the last middleware that needs to be called.
+
+        const index = this.#middlewares.length - 1;
+
+        this.#middlewares.splice(index, 0, middleware);
     }
 
     getMiddleware(type: Function): Middleware | undefined
@@ -43,9 +48,7 @@ export default abstract class ProcedureRuntime extends Runtime implements Runner
 
     #getNextHandler(fqn: string, version: Version, args: Map<string, unknown>, headers: Map<string, string>, index: number): NextHandler
     {
-        // Reverse the index so that the first middleware added is the last one to be called
-        const indexFromEnd = this.#middlewares.length - index - 1;
-        const next = this.#middlewares[indexFromEnd];
+        const next = this.#middlewares[index];
 
         if (next === undefined)
         {
diff --git a/packages/server-nodejs/src/configuration/ServerOptions.ts b/packages/server-nodejs/src/configuration/ServerOptions.ts
index f03e93f..71a8015 100644
--- a/packages/server-nodejs/src/configuration/ServerOptions.ts
+++ b/packages/server-nodejs/src/configuration/ServerOptions.ts
@@ -12,7 +12,7 @@ export const serverOptionsSchema = z
 export default class ServerOptions
 {
     #config: string;
-    #loglevel?: string;
+    #loglevel: string;
 
     constructor(config: string, loglevel = 'info')
     {
diff --git a/packages/server-nodejs/src/controllers/HealthController.ts b/packages/server-nodejs/src/controllers/HealthController.ts
index 1e82e17..d77a640 100644
--- a/packages/server-nodejs/src/controllers/HealthController.ts
+++ b/packages/server-nodejs/src/controllers/HealthController.ts
@@ -34,6 +34,8 @@ export default class HealthController
 
         this.#logger.debug('Got health status');
 
+        response.setHeader('Content-Type', 'text/plain');
+
         return response.status(200).send(healthy);
     }
 }
diff --git a/packages/server-nodejs/src/controllers/RPCController.ts b/packages/server-nodejs/src/controllers/RPCController.ts
index 1092260..a711413 100644
--- a/packages/server-nodejs/src/controllers/RPCController.ts
+++ b/packages/server-nodejs/src/controllers/RPCController.ts
@@ -168,7 +168,7 @@ export default class RPCController
 
             const result = await this.#runtime.handle(fqn, version, argsMap, headers);
 
-            this.#logger.info(`Ran procedure -> ${fqn} (${version.toString()})`);
+            this.#logger.info(`Ran procedure -> ${fqn} (v${version.toString()})`);
 
             this.#setResponseHeaders(response, headers);
 
@@ -182,7 +182,7 @@ export default class RPCController
             const message = error instanceof Error ? error.message : String(error);
             const errorData = serialize ? error : message;
 
-            this.#logger.error(`Failed to run procedure -> ${fqn} (${version.toString()}) | ${message}`);
+            this.#logger.error(`Failed to run procedure -> ${fqn} (v${version.toString()}) | ${message}`);
 
             return this.#createErrorResponse(error, errorData, response, serialize);
         }
@@ -209,10 +209,11 @@ export default class RPCController
     {
         const content = await this.#createResponseContent(result, serialize);
         const contentType = this.#createResponseContentType(content);
+        const responseContent = contentType === 'text/plain' ? String(content) : content;
 
         response.setHeader('Content-Type', contentType);
 
-        return response.status(200).send(content);
+        return response.status(200).send(responseContent);
     }
 
     async #createErrorResponse(error: unknown, errorData: unknown, response: Response, serialize: boolean): Promise<Response>


Test patch:
diff --git a/packages/runtime/test/_fixtures/interfaces/Middleware.fixture.ts b/packages/runtime/test/_fixtures/interfaces/Middleware.fixture.ts
index 5c0f863..4ef0c1e 100644
--- a/packages/runtime/test/_fixtures/interfaces/Middleware.fixture.ts
+++ b/packages/runtime/test/_fixtures/interfaces/Middleware.fixture.ts
@@ -10,7 +10,9 @@ class FirstMiddleware implements Middleware
         headers.set('first', 'yes');
         headers.set('last', '1');
 
-        return '1';
+        const result = await next();
+
+        return '1' + result;
     }
 }
 
@@ -24,7 +26,7 @@ class SecondMiddleware implements Middleware
 
         const result = await next();
 
-        return result + '2';
+        return '2' + result;
     }
 }
 
@@ -36,9 +38,7 @@ class ThirdMiddleware implements Middleware
         headers.set('third', 'yes');
         headers.set('last', '3');
 
-        const result = await next();
-
-        return result + '3';
+        return '3';
     }
 }
 
diff --git a/packages/runtime/test/services/ProcedureRuntime.spec.ts b/packages/runtime/test/services/ProcedureRuntime.spec.ts
index 7e8410d..231df34 100644
--- a/packages/runtime/test/services/ProcedureRuntime.spec.ts
+++ b/packages/runtime/test/services/ProcedureRuntime.spec.ts
@@ -22,7 +22,7 @@ describe('services/ProcedureRuntime', () =>
             expect(headers.get('first')).toBe('yes');
             expect(headers.get('second')).toBe('yes');
             expect(headers.get('third')).toBe('yes');
-            expect(headers.get('last')).toBe('1'); // The last middleware to be called is the first one to be added
+            expect(headers.get('last')).toBe('3'); // The last middleware to be called is the last one added
         });
     });
 });