# Middlewares
is similar to the Express middleware with the difference that it's a class and you can use the IoC to inject other services on its constructor.
All middlewares decorated by have one method named use()
.
This method can use all parameters decorators as you could see with the Controllers and return a promise.
# Configuration
To begin, you must add the middlewares
folder on the componentsScan
attribute in your server settings as follow :
import {Configuration} from "@tsed/common";
const rootDir = __dirname;
@Configuration({
rootDir,
mount: {
"/rest": `${rootDir}/controllers/**/**.ts`
},
componentsScan: [
`${rootDir}/services/**/**.ts`,
`${rootDir}/middlewares/**/**.ts`
]
})
export class Server {
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Then, create a new file in your middlewares folder. Create a new Class definition then add the decorator.
import {Middleware, Req} from "@tsed/common";
@Middleware()
export class CustomMiddleware {
use(@Req() req: Req) {
console.log("ID", req.id);
}
}
2
3
4
5
6
7
8
You have different usecases to declare and use a middleware as following:
- Global middleware: this middleware can be used on the Server,
- Endpoint middleware: this middleware can be used on a controller method,
- Error middleware: this middleware can be used to handle errors.
Note
Global middleware and endpoint middleware are similar, except that the Endpoint middleware can access to the last executed endpoint information.
# Global middleware
Global middlewares are generally used to handle requests before or after controllers. For example the GlobalAcceptMimesMiddleware is used to check the mime type set in the request headers and throw an error when the mime don't match with server configuration.
import {Constant, IMiddleware, Middleware, Req} from "@tsed/common";
import {NotAcceptable} from "@tsed/exceptions";
@Middleware()
export default class GlobalAcceptMimesMiddleware implements IMiddleware {
@Constant("acceptMimes")
acceptMimes: string[];
use(@Req() request: Req) {
if (!request.accepts(this.acceptMimes)) {
throw new NotAcceptable("Accepted mimes are: " + this.acceptMimes.join(", "));
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
Then add your middleware on the Server by using the right hook:
import {Configuration, Inject, PlatformApplication} from "@tsed/common";
import {GlobalAcceptMimeMiddleware} from "./GlobalAcceptMimeMiddleware";
const rootDir = __dirname;
@Configuration({
rootDir,
componentsScan: [
`${rootDir}/middlewares/**/**.js`
],
acceptMimes: ["application/json"] // add your custom configuration here
})
export class Server {
@Inject()
app: PlatformApplication;
$beforeRoutesInits() {
this.app.use(GlobalAcceptMimeMiddleware);
}
// or
$afterRoutesInit() {
this.app.use(GlobalAcceptMimeMiddleware); // But maybe is too late ;)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Endpoint middleware
Endpoint middleware is not really different from global middleware, but its goal is to handle a request before or after endpoint. It knows which endpoint is executed by using the decorator.
The following example, show you how to implement the middleware and use it with a custom decorator.
Middleware can be used on a class controller or endpoint method with the following decorators:
- or routes decorators: , , , and
import {Controller, Get, UseBefore} from "@tsed/common";
import {CustomMiddleware} from "./middlewares/CustomMiddleware";
@Controller("/test")
@UseBefore(CustomMiddleware) // global to the controller
class MyCtrl {
@Get("/")
@UseBefore(CustomMiddleware) // only to this endpoint
getContent() {
}
}
2
3
4
5
6
7
8
9
10
11
# Error middleware
Express allows you to handle any error when your middleware have 4 parameters like this:
function (error, req, res, next){}
Ts.ED has the same mechanism with decorator. Use this decorator on a middleware to create a handler which will only called when an error occurs on th decorated endpoint.
import {Err, Middleware, Next} from "@tsed/common";
@Middleware()
export class MyMiddlewareError {
use(@Err() err: unknown, @Next() next: Next) {
console.log('===> Error:', err);
}
}
2
3
4
5
6
7
8
The following example is the GlobalErrorHandlerMiddleware used by Ts.ED to handle all errors thrown by your application.
If you planed to catch errors globally see our Exception filter page.
# Specifics parameters decorators
In addition, you have these specifics parameters decorators for the middlewares:
Signature | Description |
---|---|
Inject the Express.Err service. | |
Provide the data returned by the previous middlewares. | |
Provide the endpoint information. |
# Call sequences
As you see in the previous section, a middleware can be used on different contexts:
A middleware added to a controller or endpoint level has the same constraint as the endpoint method itself. It'll be played only when the url request matches with the path associated to the controller and its endpoint method.
When a request is sent to the server all middlewares added in the Server, Controller or Endpoint with decorators will be called while a response isn't sent by one of the handlers/middlewares in the stack.
Note
send a response only when data is returned by the endpoint method or if the endpoint is the latest called endpoint for the resolved route.
TIP
The middlewares shown in the Endpoints box will be replayed as many times as it has endpoint that matches the request url.
WARNING
Only middlewares shown in the Endpoints box can use decorator to retrieve endpoint context execution.
For example:
import {Controller, Get, Next, Use, UseAfter, UseBefore, UseBeforeEach} from "@tsed/common";
@Controller("/")
@UseAfter(MdlwCtrlAfter)
@UseBefore(MdlwCtrlBefore)
@UseBeforeEach(MdlwCtrlBeforeEach)
@Use(MdlwCtrl)
export class MyCtrl {
@Get("/")
@UseBefore(MdlwBefore)
@Use(Mdlw)
@UseAfter(MdlwAfter)
endpointA(@Next() next: Next) {
console.log("EndpointA");
next();
}
@Get("/")
endpointB() {
console.log("EndpointB");
return {};
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
According to the call sequence scheme, the stack calls will be there:
- Middlewares added in Server (logger, express middleware, etc...),
- MdlwCtrlBefore,
- MdlwCtrlBeforeEach
- MdlwBefore,
- MdlwCtrl,
- MyCtrl.endpointA,
- MdlwAfter,
- SendResponse, (but no data is returned by the endpointA)
- MdlwCtrlBeforeEach
- MdlwCtrl,
- MyCtrl.endpointB,
- MdlwAfter,
- SendResponse, send a response because endpointB returns data,
- MdlwCtrlAfter, but this middleware will not be called because a response is sent.
- Middleware added in Server (not called too).
# Override existing middlewares
The decorator gives you the ability to override some internal Ts.ED middlewares.
import {Context, OriginalMiddleware, OverrideProvider} from "@tsed/common";
@OverrideProvider(OriginalMiddleware)
export class CustomMiddleware extends OriginalMiddleware {
public use(@Context() ctx: Context) {
ctx.response; // Ts.ED response
ctx.request; // Ts.ED resquest
ctx.getResponse(); // return Express.js or Koa.js response
ctx.getRequest(); // return Express.js or Koa.js request
// Do something
return super.use();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
Here we use the new Platform API to write our middleware. By using decorator and class we can get some information:
- The data returned by the last executed endpoint,
- The itself,
- The and classes abstraction. These classes allow better code abstraction by exposing methods that are agnostic to Express.js.
WARNING
Ts.ED have is own . Override this middleware is not necessary, since you can create you own middleware and register it in your server before the original GlobalErrorHandlerMiddleware. For more details, see our Exceptions documentation page.
TIP
By default, the server imports automatically your middlewares matching with this rules ${rootDir}/middlewares/**/*.ts
(See componentScan configuration).
.
├── src
│ ├── controllers
│ ├── services
│ ├── middlewares
│ └── Server.ts
└── package.json
2
3
4
5
6
7
If not, just import your middleware in your server or edit the componentScan configuration.
import {Configuration} from "@tsed/common";
import "./src/other/directory/CustomMiddleware";
@Configuration({
...
})
export class Server {
}
2
3
4
5
6
7
8
9
# Provided middlewares
- ValidationErrorMiddleware
- AcceptMimesMiddleware
-
AuthenticatedMiddleware - GlobalAcceptMimesMiddleware
-
LogIncomingRequestMiddleware - PlatformContextMiddleware
-
PlatformHeadersMiddleware - PlatformLogMiddleware
-
PlatformResponseMiddleware -
ResponseViewMiddleware -
GlobalErrorHandlerMiddleware - PlatformExceptionsMiddleware
- MultipartFileMiddleware
← Converters Pipes →
- Session & cookies
- Passport.js
- TypeORM
- Mongoose
- GraphQL
- Socket.io
- Swagger
- AJV
- Multer
- Serve static files
- Templating
- Throw HTTP Exceptions
- Customize 404
- AWS
- Jest
- Seq
- Controllers
- Providers
- Model
- Converters
- Middlewares
- Pipes
- Interceptors
- Authentication
- Hooks
- Injection scopes
- Custom providers
- Custom endpoint decorator
- Testing