惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 叶小钗
Microsoft Azure Blog
Microsoft Azure Blog
Stack Overflow Blog
Stack Overflow Blog
Jina AI
Jina AI
Vercel News
Vercel News
H
Help Net Security
Martin Fowler
Martin Fowler
美团技术团队
云风的 BLOG
云风的 BLOG
Y
Y Combinator Blog
阮一峰的网络日志
阮一峰的网络日志
MyScale Blog
MyScale Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
博客园 - 司徒正美
人人都是产品经理
人人都是产品经理
Engineering at Meta
Engineering at Meta
G
Google Developers Blog
Blog — PlanetScale
Blog — PlanetScale
MongoDB | Blog
MongoDB | Blog
宝玉的分享
宝玉的分享
小众软件
小众软件
T
Tailwind CSS Blog
WordPress大学
WordPress大学

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Mastering Custom API Response in Java Spring Boot
Jane · 2026-05-08 · via DEV Community

title
When you start building APIs in Spring Boot, things feel simple at first. You return objects, and Spring automatically converts them into JSON. But as your application grows, problems begin to appear:

  • Different APIs return different response formats

  • Error handling becomes messy

  • Frontend developers struggle to handle multiple structures

  • Debugging becomes time-consuming

This is where a Custom API Response structure becomes extremely important.

In this blog, we will deeply understand not just how to implement it, but also why each part exists and how it helps in real-world projects.

Problem with Default API Design

Let’s take a real scenario.

Case 1: Success API

{
  "id": 1,
  "name": "Ayush"
}

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Case 2: Error API

{
  "message": "User not found"
}

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Case 3: Validation Error

{
  "errors": [
    "Name is required",
    "Email is invalid"
  ]
}

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

What Breaks Here

Now the frontend must write logic like:

  • Check if id exists → success

  • Check if message exists → error

  • Check if errors exists → validation

This creates unnecessary conditional handling across web, mobile, and third-party clients.

As APIs scale, inconsistent contracts increase maintenance costs.

Solution: Standard API Response

We fix this by defining a fixed structure:

{
  "data": {},
  "success": true,
  "message": "Request successful",
  "errors": null,
  "status": "OK",
  "timestamp": "2026-04-28T10:00:00"
}

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Why Each Field Exists

  • data → Holds actual response (can be object, list, or null)

  • success → Quick boolean check (frontend friendly)

  • message → Human-readable message

  • errors → Detailed error info (useful for debugging)

  • status → HTTP status for clarity

  • timestamp → Helps in tracking and debugging issues

This makes your API predictable and easy to consume.

Step 1: StandardResponse Class

public class StandardResponse<T> {

    private T data;
    private boolean success;
    private String message;
    private Object errors;
    private HttpStatus status;
    private LocalDateTime timestamp;

    public StandardResponse(T data, boolean success, String message,
                            Object errors, HttpStatus status) {
        this.data = data;
        this.success = success;
        this.message = message;
        this.errors = errors;
        this.status = status;
        this.timestamp = LocalDateTime.now();
    }
}

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Deep Explanation

  • Generic <T>

    • Makes the class reusable for any data type
    • Example: String, User, List<User>
  • Object errors

    • Flexible → can store string, list, or map
    • Useful for validation errors
  • timestamp

    • Helps track when API was called
    • Useful in logs and debugging production issues

This class becomes the backbone of your API.

Step 2: ResponseBuilder (Why It Matters)

Without a builder, you would write this everywhere:

new StandardResponse<>(data, true, "Success", null, HttpStatus.OK);

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

This is repetitive and error-prone.

Solution:

public class ResponseBuilder {

    public static <T> StandardResponse<T> success(T data, String message) {
        return new StandardResponse<>(data, true, message, null, HttpStatus.OK);
    }

    public static <T> StandardResponse<T> error(String message, Object errors, HttpStatus status) {
        return new StandardResponse<>(null, false, message, errors, status);
    }
}

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Why This Matters

  • Reduces code duplication

  • Improves readability

  • Central place to modify response logic

  • Makes your code cleaner

  • Supports cleaner architecture

Step 3: Service Layer

public StandardResponse<String> getUser() {
    String user = "Ayush";
    return ResponseBuilder.success(user, "User fetched successfully");
}

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Why This Is Good Design

  • Business logic stays clean

  • No HTTP logic here

  • Only returns a structured response

This follows Separation of Concerns

Step 4: Controller Layer

@GetMapping("/user")
public ResponseEntity<StandardResponse<String>> getUser() {
    return ResponseEntity.ok(userService.getUser());
}

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Why Use ResponseEntity?

  • Allows control over HTTP status

  • Can add headers if needed

  • Makes API more flexible

Even though the response has a status inside, the HTTP status is still important.

Global Exception Handling (Very Important)

Instead of:

try {
   // logic
} catch(Exception e) {
   // handle
}

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Use centralized handling:

@RestControllerAdvice
public class GlobalExceptionHandler {

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Why?

  • Centralized error handling

  • No repeated try-catch

  • Cleaner code

  • Consistent error response

Step 6: Validation Handling (Advanced Understanding)

When using @Valid, Spring throws:

MethodArgumentNotValidException

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

We handle it like this:

List<String> errors = ex.getBindingResult()
    .getFieldErrors()
    .stream()
    .map(err -> err.getField() + ": " + err.getDefaultMessage())
    .toList();

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

What This Does

  • Extracts all validation errors

  • Converts them into readable messages

  • Sends them in response

Example Output:

"errors": [
  "email: must be valid",
  "name: must not be blank"
]

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Step 7: Real-World Enhancements

1. Error Codes

Instead of just a message:

"errorCode": "USER_NOT_FOUND"

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Helps frontend and logging systems.

2. Request ID (Tracing)

In microservices:

"requestId": "abc-123-xyz"

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Helps track requests across services.

3. Pagination Support

{
  "data": {
    "content": [],
    "page": 1,
    "size": 10,
    "totalElements": 100
  }
}

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Important for large datasets.

4. Execution Time

Track performance:

long start = System.currentTimeMillis();

Enter fullscreen mode Exit fullscreen mode

Use our Online Code Editor

Helps optimize slow APIs.

Common Mistakes to Avoid

  • Returning raw entities directly

  • Mixing multiple response formats

  • Not handling exceptions globally

  • Ignoring validation errors

  • Hardcoding messages everywhere

Have a great one!!!

Author: Ayush Shrivastava


Thank you for being a part of the community

Before you go:

Whenever you’re ready

There are 4 ways we can help you become a great backend engineer:

  • The MB Platform: Join thousands of backend engineers learning backend engineering. Build real-world backend projects, learn from expert-vetted courses and roadmaps, track your learning and set schedules, and solve backend engineering tasks, exercises, and challenges.
  • The MB Academy: The “MB Academy” is a 6-month intensive Advanced Backend Engineering Boot Camp to produce great backend engineers.
  • Join Backend Weekly: If you like posts like this, you will absolutely enjoy our exclusive weekly newsletter, sharing exclusive backend engineering resources to help you become a great Backend Engineer.
  • Get Backend Jobs: Find over 2,000+ Tailored International Remote Backend Jobs or Reach 50,000+ backend engineers on the #1 Backend Engineering Job Board.