java
30 lines · 7 steps
Header-driven endpoints in a Spring controller
A REST controller reads path variables and request headers, then handles a missing-header error locally.
Explained by
highlit
1@RestController
2@RequestMapping("/api/reports")
3public class ReportController {
4
5 private final ReportService reportService;
6
7 public ReportController(ReportService reportService) {
8 this.reportService = reportService;
9 }
10
11 @GetMapping("/{id}")
12 public ResponseEntity<ReportView> getReport(
13 @PathVariable Long id,
14 @RequestHeader("X-Tenant-Id") String tenantId,
15 @RequestHeader(value = "X-Report-Format", defaultValue = "summary") String format) {
16
17 ReportView view = reportService.render(id, tenantId, format);
18 return ResponseEntity.ok()
19 .header("X-Report-Format", format)
20 .body(view);
21 }
22
23 @ExceptionHandler(MissingRequestHeaderException.class)
24 public ResponseEntity<ApiError> handleMissingHeader(MissingRequestHeaderException ex) {
25 ApiError error = new ApiError(
26 HttpStatus.BAD_REQUEST.value(),
27 "Missing required header: " + ex.getHeaderName());
28 return ResponseEntity.badRequest().body(error);
29 }
30}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Request headers can carry cross-cutting context like tenant identity without polluting the URL path.
- 2Header options with defaults keep some inputs optional while others stay mandatory.
- 3A controller-scoped @ExceptionHandler turns framework exceptions into clean, structured error responses.
Related explainers
java
public final class Ulid { private static final char[] ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ".toCharArray(); private static final SecureRandom RANDOM = new SecureRandom();
How to generate a ULID in Java
base32-encoding
bit-manipulation
identifiers
Intermediate
8 steps
java
public final class CaseConverter { private static final Pattern CAMEL_BOUNDARY = Pattern.compile("([a-z0-9])([A-Z])|([A-Z]+)([A-Z][a-z])");
Converting camelCase to snake_case in Java
regex
string-manipulation
utility-class
Intermediate
7 steps
java
@Component public class RegionCacheWarmer implements SmartInitializingSingleton { private static final Logger log = LoggerFactory.getLogger(RegionCacheWarmer.class);
Warming a Spring cache at startup
caching
startup-hook
dependency-injection
Intermediate
7 steps
java
public final class EmailNormalizer { private static final Pattern EMAIL_PATTERN = Pattern.compile( "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"
Normalizing email addresses in Java
validation
regex
normalization
Intermediate
8 steps
rust
use axum::{ extract::{FromRequestParts, Host}, http::{request::Parts, StatusCode}, };
Multi-tenant DB routing in Axum extractors
multi-tenancy
extractors
connection-pooling
Advanced
8 steps
java
@RestController @RequestMapping("/api/products") @RequiredArgsConstructor public class ProductBatchController {
Batch JSON Merge Patch in Spring
json-merge-patch
rest-api
partial-update
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/header-driven-endpoints-in-a-spring-controller-explained-java-9e13/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.