Skip to content
Download

Creating Middleware

A Mach middleware can be any class that provides an invoke() method with the expected signature.

There is no middleware base class to inherit from.

A middleware class implements:

void invoke(mach::Context& context, mach::Next& next);

For example:

class LoggingMiddleware {
public:
explicit LoggingMiddleware(mach::Logger& logger)
: m_logger(logger) {}
void invoke(mach::Context& context, mach::Next& next) {
m_logger.info("Before handler");
context.response.setHeader("X-Middleware", "Logging");
next();
m_logger.info("After handler");
}
private:
mach::Logger& m_logger;
};

Mach calls invoke() when a request reaches the middleware.

The two parameters provide access to the current request pipeline:

  • mach::Context& context exposes the current request and response.
  • mach::Next& next represents the next step in the pipeline.

The Mach CLI can generate a middleware class for you:

Terminal window
mach generate middleware logging

This creates a LoggingMiddleware with the required invoke() method, ready for your middleware logic.

Call next() to continue processing:

void invoke(mach::Context& context, mach::Next& next) {
// Runs before later middleware or the endpoint
next();
// Runs after later middleware or the endpoint
}

Code before next() runs on the way into the pipeline. Code after it runs when control returns.

This makes middleware useful for behavior that needs to surround endpoint execution.

A middleware does not have to call next().

If it produces a response and returns without invoking the next step, later middleware and the matched endpoint are skipped:

void invoke(mach::Context& context, mach::Next& next) {
if (!context.request.containsHeader("X-Required")) {
context.response.status(mach::http::StatusCode::BadRequest);
context.response.body("Missing required header");
return;
}
next();
}

This is known as short-circuiting the pipeline.

It is useful when the middleware can determine that the request should not continue.

Middleware receives the same mach::Context& used by minimal API handlers.

For example:

void invoke(mach::Context& context, mach::Next& next) {
const auto method = context.request.method();
context.response.setHeader("X-Processed-By", "Mach");
next();
}

This allows middleware to inspect or modify request and response data before and after endpoint execution.

Middleware classes can receive dependencies through their constructor:

class LoggingMiddleware {
public:
explicit LoggingMiddleware(mach::Logger& logger)
: m_logger(logger) {}
void invoke(mach::Context& context, mach::Next& next) {
m_logger.info("Before handler");
next();
m_logger.info("After handler");
}
private:
mach::Logger& m_logger;
};

The dependency list is provided when the middleware is registered.

Registration and dependency declaration are covered in the next guide.


Next, you’ll learn how to register middleware and control its position in the request pipeline.