Skip to content

Commit

Permalink
fix(binding-http): middleware as a function
Browse files Browse the repository at this point in the history
  • Loading branch information
ilbertt committed Jun 28, 2023
1 parent a2a2e63 commit b8f3bde
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 48 deletions.
10 changes: 5 additions & 5 deletions packages/binding-http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,17 +310,17 @@ The exposed thing on the internal server will product form URLs such as:

### Adding a middleware

HttpServer supports the addition of **middleware** to handle the raw HTTP requests before they hit the Servient. In the middleware you can run some logic to filter and eventually reject HTTP requests (e.g. based on some custom headers).
HttpServer supports the addition of **middleware** to handle the raw HTTP requests before they hit the Servient. In the middleware function, you can run some logic to filter and eventually reject HTTP requests (e.g. based on some custom headers).

This can be done by passing an instance of HttpMiddleware to the HttpServer constructor.
This can be done by passing a middleware function to the HttpServer constructor.

```js
const { Servient } = require("@node-wot/core");
const { HttpMiddleware, HttpServer } = require("@node-wot/binding-http");
const { HttpServer } = require("@node-wot/binding-http");

const servient = new Servient();

const middleware = new HttpMiddleware(async (req, res, next) => {
const middleware = async (req, res, next) => {
// For example, reject requests in which the X-Custom-Header header is missing
// by replying with 400 Bad Request
if (!req.headers["x-custom-header"]) {
Expand All @@ -330,7 +330,7 @@ const middleware = new HttpMiddleware(async (req, res, next) => {
}
// Pass all other requests to the WoT Servient
next();
});
};

const httpServer = new HttpServer({
port,
Expand Down
44 changes: 12 additions & 32 deletions packages/binding-http/src/http-server-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,19 @@
* HTTP Middleware for the HTTP Server
*/

import { createLoggers } from "@node-wot/core";
import * as http from "http";

const { debug } = createLoggers("binding-http", "http-server-middleware");

/**
* A function that handles a request and passes it to the WoT Servient.
* See {@link HttpMiddleware} for an example.
* @param req The HTTP request.
* @param res The HTTP response.
* @param next Call this function to pass the request to the WoT Servient.
*/
export type MiddlewareRequestHandler = (
req: http.IncomingMessage,
res: http.ServerResponse,
next: () => void
) => Promise<void>;

/**
* A middleware for the HTTP server, which can be used to intercept requests before they are handled by the WoT Servient.
* A middleware function for the HTTP server, which can be used to intercept requests before they are handled by the WoT Servient.
*
* Example:
* ```javascript
* import { Servient } from "@node-wot/core";
* import { HttpMiddleware, HttpServer } from "@node-wot/binding-http";
* import { HttpServer, MiddlewareRequestHandler } from "@node-wot/binding-http";
*
* const servient = new Servient();
*
* const middleware = new HttpMiddleware(async (req, res, next) => {
* const middleware: MiddlewareRequestHandler = async (req, res, next) => {
* // For example, reject requests in which the X-Custom-Header header is missing
* // by replying with 400 Bad Request
* if (!req.headers["x-custom-header"]) {
Expand All @@ -55,7 +39,7 @@ export type MiddlewareRequestHandler = (
* }
* // Pass all other requests to the WoT Servient
* next();
* });
* };
* const httpServer = new HttpServer({
* port,
Expand All @@ -68,16 +52,12 @@ export type MiddlewareRequestHandler = (
* // ...
* });
* ```
* @param req The HTTP request.
* @param res The HTTP response.
* @param next Call this function to pass the request to the WoT Servient.
*/
export default class HttpMiddleware {
public handler: MiddlewareRequestHandler;

constructor(handler: MiddlewareRequestHandler) {
this.handler = handler;
}

public handleRequest(req: http.IncomingMessage, res: http.ServerResponse, next: () => void): Promise<void> {
debug("Hit middleware");
return this.handler(req, res, next);
}
}
export type MiddlewareRequestHandler = (
req: http.IncomingMessage,
res: http.ServerResponse,
next: () => void
) => Promise<void>;
8 changes: 4 additions & 4 deletions packages/binding-http/src/http-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import slugify from "slugify";
import { ThingDescription } from "wot-typescript-definitions";
import * as acceptLanguageParser from "accept-language-parser";
import { ActionElement, EventElement, PropertyElement } from "wot-thing-description-types";
import HttpMiddleware from "./http-server-middleware";
import { MiddlewareRequestHandler } from "./http-server-middleware";

const { debug, info, warn, error } = createLoggers("binding-http", "http-server");

Expand All @@ -66,7 +66,7 @@ export default class HttpServer implements ProtocolServer {
private readonly httpSecurityScheme: string = "NoSec"; // HTTP header compatible string
private readonly validOAuthClients: RegExp = /.*/g;
private readonly server: http.Server | https.Server = null;
private readonly middleware: HttpMiddleware = null;
private readonly middleware: MiddlewareRequestHandler = null;
private readonly things: Map<string, ExposedThing> = new Map<string, ExposedThing>();
private servient: Servient = null;
private oAuthValidator: Validator;
Expand Down Expand Up @@ -112,7 +112,7 @@ export default class HttpServer implements ProtocolServer {
this.scheme = "https";
this.server = https.createServer(options, (req, res) => {
if (this.middleware) {
this.middleware.handleRequest(req, res, () => {
this.middleware(req, res, () => {
this.handleRequest(req, res);
});
} else {
Expand All @@ -123,7 +123,7 @@ export default class HttpServer implements ProtocolServer {
this.scheme = "http";
this.server = http.createServer((req, res) => {
if (this.middleware) {
this.middleware.handleRequest(req, res, () => {
this.middleware(req, res, () => {
this.handleRequest(req, res);
});
} else {
Expand Down
7 changes: 3 additions & 4 deletions packages/binding-http/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,17 @@

import * as TD from "@node-wot/td-tools";
import { Method } from "./oauth-token-validation";
import HttpMiddleware from "./http-server-middleware";
import { MiddlewareRequestHandler } from "./http-server-middleware";

export { default as HttpServer } from "./http-server";
export { default as HttpClient } from "./http-client";
export { default as HttpClientFactory } from "./http-client-factory";
export { default as HttpsClientFactory } from "./https-client-factory";
export { default as HttpMiddleware } from "./http-server-middleware";
export { MiddlewareRequestHandler } from "./http-server-middleware";
export * from "./http-server";
export * from "./http-client";
export * from "./http-client-factory";
export * from "./https-client-factory";
export * from "./http-server-middleware";

export interface HttpProxyConfig {
href: string;
Expand All @@ -46,7 +45,7 @@ export interface HttpConfig {
serverKey?: string;
serverCert?: string;
security?: TD.SecurityScheme;
middleware?: HttpMiddleware;
middleware?: MiddlewareRequestHandler;
}

export interface OAuth2ServerConfig extends TD.SecurityScheme {
Expand Down
6 changes: 3 additions & 3 deletions packages/binding-http/test/http-server-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { Content, createLoggers, ExposedThing, Helpers } from "@node-wot/core";
import { DataSchemaValue, InteractionInput, InteractionOptions } from "wot-typescript-definitions";
import chaiAsPromised from "chai-as-promised";
import { Readable } from "stream";
import HttpMiddleware from "../src/http-server-middleware";
import { MiddlewareRequestHandler } from "../src/http-server-middleware";

const { debug, error } = createLoggers("binding-http", "http-server-test");

Expand All @@ -51,14 +51,14 @@ class HttpServerTest {
}

@test async "should use middleware if provided"() {
const middleware = new HttpMiddleware(async (req, res, next) => {
const middleware: MiddlewareRequestHandler = async (req, res, next) => {
if (req.url.endsWith("testMiddleware")) {
res.statusCode = 401;
res.end("Unauthorized");
} else {
next();
}
});
};

const httpServer = new HttpServer({
port,
Expand Down

0 comments on commit b8f3bde

Please sign in to comment.