Skip to content

Commit

Permalink
Extended middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
FlorianRappl committed Aug 22, 2022
1 parent ff039c7 commit abbb91a
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Removed support for Node.js below 12
- Added support for asynchronous creators (#54)
- Added optional `direction` parameter to middlewares (#53)
- Updated dependencies

## 0.14.3
Expand Down
33 changes: 33 additions & 0 deletions docs/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,36 @@ module.exports = function (cookieName) {
};
};
```

The `setup` and the creator function can both be `async`, i.e., return a `Promise`.

```js
module.exports = async function (cookieName) {
// do something that needs to be awaited, e.g.,
const answerToLife = await computeAnswerToEverything();
return (req, res, next) => {
res.headers['set-cookie'] = `${cookieName}=${answerToLife}`;
next();
};
};
```

Another thing to consider is the **direction** that the middleware is applied. By default, the middleware is applied in the **incoming direction** (`in`), i.e., *before* the request has been processed by any injector. Like any middleware, it will be processed before the response will be send to the client.

Another option is to change the `direction` to **outgoing** (`out`):

```json
{
"middlewares": [
{
"source": "some-middleware-package",
"options": [],
"direction": "out"
}
]
}
```

Now this will be applied *after* an injector has been hit.

**Note**: Outgoing middleware is not really useful for modifying responses as the response has already been prepared. The main purpose of an outgoing middleware is to close resources or write out details about the request / response.
10 changes: 10 additions & 0 deletions src/server/core/webserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ export class WebServer extends EventEmitter implements BaseKrasServer {
storage: multer.memoryStorage(),
limits: { files: 5, fileSize: sizeInMB * 1024 * 1024 },
});
this.app.use((req, res, next) => {
//prepares the req / res system
req.addedHeaders = {};
req.removedHeaders = [];
req.addedQuery = {};
req.removedQuery = ['_'];
res.middlewares = [];
res.prepared = undefined;
next();
});
this.app.use(upload.any());
this.app.use(
text({
Expand Down
27 changes: 25 additions & 2 deletions src/server/helpers/middlewares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ async function createMiddleware(
config: KrasConfiguration,
baseDir: string,
source: string,
direction: 'in' | 'out',
options: Array<any>,
) {
const creator =
Expand All @@ -51,6 +52,7 @@ async function createMiddleware(
options,
source,
active: true,
direction,
handler,
};
}
Expand All @@ -65,7 +67,27 @@ function integrateMiddlewares(server: KrasServer) {
const all = server.at('*');

for (const middleware of server.middlewares) {
all.any(middleware.handler);
all.any((req, res, next) => {
if (middleware.active) {
if (middleware.direction === 'in') {
return middleware.handler(req, res, next);
} else if (middleware.direction === 'out') {
res.middlewares.push(
() =>
new Promise<any>((resolve, reject) => {
try {
middleware.handler(req, res, resolve);
} catch (e) {
reject(e);
}
}),
);
return next();
}
}

next();
});
}
}
}
Expand All @@ -77,7 +99,8 @@ export async function withMiddlewares(server: KrasServer, config: KrasConfigurat
const source = definition.source;
const baseDir = definition.baseDir || config.directory;
const options = definition.options || [];
const middleware = await createMiddleware(server, config, baseDir, source, options);
const direction = definition.direction || 'in';
const middleware = await createMiddleware(server, config, baseDir, source, direction, options);

if (middleware) {
server.middlewares.push(middleware);
Expand Down
37 changes: 32 additions & 5 deletions src/server/injectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,24 @@ function getTarget(targets: Array<string>, url: string) {

function normalizeRequest(targets: Array<string>, req: Request): KrasRequest {
const target = getTarget(targets, req.originalUrl) || '';
const url = req.originalUrl.substr(target.length);
const query = Object.assign({}, req.query) as Record<string, string>;
const headers = Object.assign({}, req.headers) as Record<string, string>;
const url = req.originalUrl.substring(target.length);

const query = Object.assign(
{
...req.addedQuery,
},
req.query,
) as Record<string, string>;

const headers = Object.assign(
{
...req.addedHeaders,
},
req.headers,
) as Record<string, string>;

let content: any;

if (req.headers['content-type'] && req.headers['content-type'].search('multipart/form-data') !== -1) {
const formData = new FormData();
typeof req.body === 'object' &&
Expand All @@ -93,7 +107,14 @@ function normalizeRequest(targets: Array<string>, req: Request): KrasRequest {
}

const method = typeof req.method === 'string' ? req.method : 'GET';
delete query._;

for (const name of req.removedHeaders) {
delete headers[name];
}

for (const name of req.removedQuery) {
delete query[name];
}

return {
url,
Expand Down Expand Up @@ -126,14 +147,20 @@ function handleRequest(server: KrasServer, req: KrasRequest, res: Response) {

server.emit('request', req);

tryInjectors(injectors, req).then((ans) => {
tryInjectors(injectors, req).then(async (ans) => {
res.prepared = ans;

if (!ans) {
server.emit('missing', req);
ans = fromMissing(req.url);
} else {
server.emit('response', ans);
}

for (const middleware of res.middlewares) {
await middleware();
}

sendResponse(req, ans, res);
});
}
Expand Down
16 changes: 16 additions & 0 deletions src/server/types/kras-express.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
import { Request, Response, NextFunction } from 'express';
import { EventEmitter } from 'events';

declare global {
namespace Express {
interface Request {
addedHeaders: Record<string, string>;
removedHeaders: Array<string>;
addedQuery: Record<string, string>;
removedQuery: Array<string>;
}

interface Response {
middlewares: Array<() => Promise<void>>;
prepared: any;
}
}
}

export interface KrasServerHook {
handle(req: Request, res: Response): void;
rate(req: Request): number;
Expand Down
2 changes: 2 additions & 0 deletions src/server/types/kras-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { KrasServerHandler } from './kras-express';

export interface KrasMiddleware {
source: string;
direction: 'in' | 'out';
options: Array<any>;
active: boolean;
handler: KrasServerHandler;
}

export interface KrasMiddlewareDefinition {
source: string;
direction?: 'in' | 'out';
baseDir?: string;
options?: Array<any>;
}

0 comments on commit abbb91a

Please sign in to comment.