Custom Middleware
Why This Is Asked
Middleware is the backbone of the request pipeline in modern web frameworks. Interviewers want to see if you can extend the pipeline for cross-cutting concerns like logging, authentication, or custom error handling.
Key Concepts
- Middleware are components that form a pipeline to handle requests and responses.
- Each component can choose to pass the request to the next component in the pipe.
- Typical use cases: Logging, Exception Handling, Request Localization, Response Caching.
- Order matters: The sequence in which middleware is added determines the execution order.
Answers by Technology
+ Add VariantExpected Answer (.NET 10 / C# 14)
In ASP.NET Core, middleware is a class that resides in the request pipeline. To write a custom one, you typically need a class with a constructor that takes RequestDelegate and an InvokeAsync method.
Real-time use case: A “Request Timing” middleware that logs how long each API request takes to process.
Why It Matters
Middleware allows you to separate cross-cutting concerns from your business logic. Instead of putting logging or auth logic in every controller action, you put it in a single middleware that wraps the entire request.
Code Example
public class RequestTimingMiddleware
{
private readonly RequestDelegate _next;
public RequestTimingMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context)
{
var watch = Stopwatch.StartNew();
// Pass to the next middleware in the pipe
await _next(context);
watch.Stop();
Console.WriteLine($"Request {context.Request.Path} took {watch.ElapsedMilliseconds}ms");
}
}
// Registration in Program.cs
// app.UseMiddleware<RequestTimingMiddleware>();
Common Mistakes
- Incorrect Order: Placing error-handling middleware after the middleware that might throw an exception.
- Forgetting
await _next(context): This will short-circuit the pipeline, and no further middleware (or your controllers) will be executed.
Follow-up Questions
- Singleton vs Scoped Middleware? (Answer: Middleware is usually a Singleton. If you need Scoped services, you must inject them into the
InvokeAsyncmethod, not the constructor). - What is the difference between
app.Useandapp.Run? (Answer:app.Usepasses to the next middleware;app.Runis a terminal middleware that ends the pipeline).
Expected Answer (Java 26 / Spring Boot)
In the Java Spring ecosystem, the equivalent of middleware is a Filter (Servlet API) or an Interceptor (Spring MVC).
- Servlet Filter: Operates at the lowest level of the web request.
- HandlerInterceptor: Higher level, has access to the Spring
HandlerandModelAndView.
Real-time use case: A “Logging Filter” that logs every incoming request’s method and URI before it reaches the controller.
Why It Matters
Filters allow you to implement cross-cutting concerns (logging, security, CORS, compression) in a centralized way. This keeps your business logic (Controllers) clean and focused on their primary task.
Code Example
@Component
public class RequestLoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
System.out.println("Request: " + req.getMethod() + " " + req.getRequestURI());
// Pass to the next filter in the chain
chain.doFilter(request, response);
}
}
Common Mistakes
- Order of execution: Using
@OrderorFilterRegistrationBeanto ensure security filters run before logging filters. - Blocking the chain: Forgetting to call
chain.doFilter(), which will stop the request from ever reaching your Controller.
Follow-up Questions
- Filter vs Interceptor? (Answer: Filters are part of the Servlet container; Interceptors are part of the Spring Framework and have access to Spring-specific metadata).
- OncePerRequestFilter: Why use it? (Answer: To ensure a filter is executed exactly once per request, even if there are internal forwards or includes).
Expected Answer (PHP 8.5 / Laravel)
In Laravel, middleware provides a convenient mechanism for inspecting and filtering HTTP requests entering your application.
Real-time use case: An “Active Subscription” middleware that checks if a logged-in user has an active paid plan before allowing them to access certain routes.
Why It Matters
Middleware allows you to centralize logic that applies to many routes. Instead of checking for a subscription in 50 different controller methods, you write it once and apply it to a route group.
Code Example
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class EnsureUserIsSubscribed
{
public function handle(Request $request, Closure $next)
{
if ($request->user() && ! $request->user()->isSubscribed()) {
return redirect('billing');
}
return $next($request);
}
}
Common Mistakes
- Heavy Logic: Putting complex database queries in middleware that runs on every request can significantly slow down the entire app.
- Forgetting
return $next($request): This will break the request, and the user will see a blank page as the controller is never reached.
Follow-up Questions
- Global vs Route Middleware? (Answer: Global middleware runs on every request; Route middleware is assigned only to specific routes or groups).
- What is ‘Middleware Terminate’? (Answer: A method that runs after the response has been sent to the browser, useful for logging or cleanup).