Error Handling in Spring Boot: Controllers vs Filters

What Two paths: controller exceptions vs pre-controller (filters/interceptors) exceptions. Single response shape via GlobalExceptionHandler for both paths. Flow (who catches what): Controller throws → handled by @ControllerAdvice methods. Filter/interceptor throws → not handled by @ControllerAdvice unless you forward via HandlerExceptionResolver. Why Consistency: avoid container default error pages/messages. Control: send structured GenericResponse with proper HTTP codes. How Global handler (GlobalExceptionHandler): @ControllerAdvice class GlobalExceptionHandler { @ExceptionHandler(UnAuthorizedExceptionThrowable::class) fun handleUnauthorized(ex: UnAuthorizedExceptionThrowable, req: WebRequest): ResponseEntity<GenericResponse<Nothing>> { val body = GenericResponse<Nothing>( responseType = ResponseType.FAIL, message = ex.errorMessage, code = ex.code, type = ex.errorMessage ) return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(body) } @ExceptionHandler(Exception::class) fun handleGeneric(ex: Exception, req: WebRequest) = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( GenericResponse<Nothing>( responseType = ResponseType.ERROR, message = ex.message ?: "Internal server error", code = HttpStatus.INTERNAL_SERVER_ERROR.value(), type = "Internal server error" ) ) } Explanation: ...

October 14, 2025 · 2 min · 383 words · Sagar Nayak

Security Setup in Spring Boot: CORS, JWT, and API Tiers

What CORS blocks non-whitelisted origins in AppSecurityConfig. JWT is validated for protected endpoints in JwtAuthenticationFilter using AuthenticationManagerJWT. API tiers restrict access even with a valid token; higher tiers grant access to more endpoints. Flow (request lifecycle): Incoming request → CORS applied → non-whitelisted origins blocked. Public/No-Auth endpoints bypass JWT checks. Protected endpoints → JWT extracted and validated. Tier authorization matched against requested API tier. On success, controller executes; on failure, error is routed to global handler. Why Prevent misuse from unwanted domains via strict CORS. Reject bad tokens: expired, blocked, reused/refresh-misuse. Enforce progression: open → tier 4 → tier 3 → tier 2 → tier 1 as business rules demand. How CORS configuration (AppSecurityConfig.corsConfigurationSource()): @Bean fun corsConfigurationSource(): CorsConfigurationSource { val configuration = CorsConfiguration() configuration.allowedOrigins = listOf( "http://localhost:3000", "https://yourdomain.com" ) configuration.allowedMethods = listOf("GET","POST","PUT","DELETE","OPTIONS","PATCH") configuration.allowedHeaders = listOf( "Authorization","Content-Type","X-Requested-With","Accept","Origin", KeywordsAndConstants.HEADER_TRACKING_ID, KeywordsAndConstants.HEADER_API_KEY, KeywordsAndConstants.HEADER_OTP, KeywordsAndConstants.HEADER_AUTH_TOKEN ) configuration.allowCredentials = true configuration.exposedHeaders = listOf( KeywordsAndConstants.HEADER_TRACKING_ID, KeywordsAndConstants.HEADER_API_TIER ) val source = UrlBasedCorsConfigurationSource() source.registerCorsConfiguration("/**", configuration) return source } Explanation: ...

September 18, 2025 · 3 min · 553 words · Sagar Nayak

Expense Tracker (Part 4/5): Backend APIs

Series links: Part 1/5 - Introduction Part 2/5 - Database Planning Part 3/5 - AWS Setup Part 4/5 - Backend APIs (you are here) Part 5/5 - Frontend What A tiny set of APIs to save entries with files, search them, get suggestions, and export CSV. Why Clear, stable contracts make the frontend simple. You can implement these endpoints in any backend framework. How Use your own domain names. The example hostnames below are placeholders. ...

July 19, 2025 · 2 min · 313 words · Sagar Nayak