๐ง What REALLY Happens When You Hit a Spring Boot REST API?
๐ฅ Inside the Hidden World of Filters, Interceptors & DispatcherServlet
๐ฌ Intro: “It’s Just a Simple API Call…” — Said Every Developer Before Debugging It
You hit this:
GET http://localhost:8080/api/user/42
๐ฏ And your controller returns the user info. Done, right?
๐ LOL no.
Welcome to Spring Boot, where your request goes on a rollercoaster ride through filters, interceptors, servlet containers, exception resolvers, and more — before it even thinks about reaching your controller.
Let’s deep-dive into the secret life of a REST API call in Spring Boot — with ๐ internal mechanics, ๐ฑ common mistakes
⚙️ 1. ๐ช The Request Arrives at... The Bouncer (Tomcat)
Spring Boot has an embedded server (usually Tomcat). When your app starts, it's like opening a door at a nightclub. The request knocks. ๐บ
Tomcat says:
"Who dis? ๐คจ"
And then it lets the HTTP request enter.
๐ง Technically: Tomcat parses the socket connection and sends the request into the Servlet layer.
๐งฐ 2. ๐ Filters Step In – “We Check Everyone!”
@Component
public class MyFilter implements Filter {
public void doFilter(...) {
// CORS? Auth header? Logging? All here
chain.doFilter(request, response);
}
}
๐ What They Do:
- Logging ๐ชต
- Header checks ๐งพ
- CORS setup ๐
- JWT parsing ๐
⚠️ Can’t access Spring beans easily (they live in the servlet world ๐).
Joke:
“Filters are like your mom at the door. If your hair’s messy or token is missing, she won’t let you go to the party.” ๐
๐ง 3. ๐ฉ Enter the DispatcherServlet — The Real Boss
Spring's legendary DispatcherServlet
is the Front Controller.
It’s the guy in the suit standing behind the scenes, pointing where every request should go.
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
๐งญ Responsibilities:
- Picks the right controller ๐ค
- Handles exceptions ๐ฅ
- Sends responses ๐
- Makes sure your REST endpoint actually gets called
๐ฆ 4. ๐ต️ Interceptors Arrive – “We See What You Do”
Unlike filters, interceptors live in Springland, where you get DI, beans, and control. ๐
@Component
public class MyInterceptor implements HandlerInterceptor {
public boolean preHandle(...) { }
public void postHandle(...) { }
public void afterCompletion(...) { }
}
✅ preHandle()
— Before Controller
- Block request? Return
false
. ๐ซ - Start timing? ⏱️
- Check session? ๐
๐ postHandle()
— After Controller
- Modify
ModelAndView
๐ญ - Log what controller returned ✅
- Inject extra data before view is rendered ๐
๐ซ You can't modify the JSON response here if it’s a REST controller.
๐ afterCompletion()
— After Response Sent
- Log request duration ⏱️
- Cleanup (ThreadLocal, MDC) ๐งน
- Log exceptions ๐ค
❌ You cannot modify the response here; it’s already committed!
๐ฏ 5. ๐ฏ Handler Mapping – “Where’s This Request Supposed to Go?”
Spring finds the matching controller based on:
- URL path ๐ฃ️
- HTTP method ๐
- Annotations like
@GetMapping
,@PostMapping
@GetMapping("/api/user/{id}")
public User getUser(@PathVariable Long id) {
return userService.findUser(id);
}
๐ค 6. Your Controller Finally Runs ๐
Spring injects everything you love:
@PathVariable
,@RequestParam
,@RequestBody
- Autowired beans
- RequestContext, Headers, etc.
๐ฃ 7. Boom! Exceptions? Enter @ControllerAdvice ๐ฌ
@ControllerAdvice
public class MyErrorHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<?> handleIt() {
return ResponseEntity.status(404).body("No user, bro!");
}
}
✅ Spring checks for matching exception handlers.
❌ If none are found → you get a white-label error page (uglyyyy).
๐ค 8. Response Goes Back (Backwards Flow)
The response now goes through:
ResponseBodyAdvice
๐ ️- Interceptors:
postHandle()
→afterCompletion()
๐ - Servlet Filters (again) ๐ฆ
- Embedded server (Tomcat) ✉️
- The client gets the final response ๐
๐บ️ The Full Lifecycle Map
Client
↓
๐ Embedded Server (Tomcat)
↓
๐ Filters (Servlet API)
↓
๐ฉ DispatcherServlet
↓
๐ต️ Interceptor.preHandle()
↓
๐งญ Handler Mapping
↓
๐ฏ Controller Logic
↓
๐งน Interceptor.postHandle()
↓
๐ฆ ResponseBodyAdvice
↓
๐งผ Interceptor.afterCompletion()
↓
๐ Filters (post)
↓
✉️ Response to Client
๐ฏ Should I Set Headers in a Filter or an Interceptor? ๐ค
Great question! You might be wondering:
“If I can add headers in a filter, why should I ever use an interceptor?” ๐คจ
๐ ️ Short Answer:
✅ Both can add headers.
๐ซ But filters don’t know which controller is being called.
๐ก Interceptors do, and they have full Spring context.
๐ฌ Case Studies to Compare
1️⃣ Global Headers — Use a Filter ✅
// Filter example
response.setHeader("X-App-Version", "1.0.9");
response.setHeader("X-Frame-Options", "DENY");
Perfect for:
- CORS headers ๐
- Security headers ๐
- Trace IDs ๐งต
2️⃣ Controller-Specific Headers — Use an Interceptor ๐ก
// Interceptor example
public void postHandle(...) {
if (handler instanceof HandlerMethod hm &&
hm.hasMethodAnnotation(MySpecialHeader.class)) {
response.setHeader("X-Special", "true");
}
}
Interceptors know:
- Which controller method is running ๐ง
- What annotations are present ๐
- Can access Spring beans! ๐ฑ
3️⃣ Modify Headers After Controller — Use Interceptor or ResponseBodyAdvice ๐
If your controller is REST and you need to add headers *after* business logic:
- ✅ Interceptor’s
postHandle()
(for headers) - ✅
ResponseBodyAdvice
(for body + headers๐ฌ Interviewer May Ask:
“Can you set headers in a filter?” ✅ Yes, but only generic ones.
“Can you modify headers based on the controller?” ❌ Not in filters. ✅ Use interceptors!
๐ฏ Rule of Thumb:
- Use filters when you need to do something BEFORE Spring kicks in
- Use interceptors when you want access to Spring context, beans, and controller logic
๐ Bonus Tip:
For REST APIs, add metadata headers like:
response.setHeader("X-Request-ID", requestId);
response.setHeader("X-User-ID", userId);
This helps in:
- ๐ Distributed tracing
- ๐ Debugging logs across microservices
- ๐ Monitoring APIs under load
๐ฌ What About You?
Ever confused filters and interceptors in a live project or interview? ๐
Did someone add response headers in afterCompletion()
and wonder why they didn't show up?
Share your war stories in the comments below ๐
๐งช Interview Questions You’ll Crush After Reading This
❓ Question | ✅ Answer |
---|---|
Filter vs Interceptor? | Filter = Servlet level Interceptor = Spring MVC level |
Can I block request in preHandle() ? |
Yes, return false to stop the flow |
Can I modify response in afterCompletion() ? |
❌ No. Response already committed |
Where to log time taken? | afterCompletion() is ideal ⏱️ |
Filter throws exception. Who handles it? | Global exception handler won’t catch unless inside Spring context |
๐ช Wrapping Up: You Just Became a Request Flow Wizard ๐ง
Most devs debug controller issues without knowing filters or interceptors even touched the request.
But not you. ๐ช You now know exactly who does what, when, and why.
Whether it’s logging, security, tracing, or performance — this internal flow gives you superpowers in both interviews and real projects.
๐ฌ Your Turn:
Ever spent hours debugging a request that mysteriously vanished? Was it a filter, a missing header, or a short-circuiting preHandle()? ๐ Drop your war stories in the comments ๐
Comments
Post a Comment