DEV Community

Er. Bhupendra
Er. Bhupendra

Posted on

PART 5 :CONTROLLER ALL CONCEPT IN SPRINGBOOT PROJECT

❌ NAHI! Koi Inbuilt ApiResponse Nahi Hai Spring Boot Mein


Confusion Clear Karte Hain

Spring Boot Mein Kya Inbuilt Hai?

✅ ResponseEntity        → Inbuilt (org.springframework.http)
✅ HttpStatus            → Inbuilt (org.springframework.http)
✅ HttpHeaders           → Inbuilt (org.springframework.http)
✅ MediaType             → Inbuilt (org.springframework.http)

❌ ApiResponse           → INBUILT NAHI HAI (khud banana padta)
❌ PageResponse          → INBUILT NAHI HAI (khud banana padta)
❌ ErrorResponse         → INBUILT NAHI HAI (khud banana padta)
Enter fullscreen mode Exit fullscreen mode

Toh Companies/Developers Kya Karte Hain?

3 Approaches:

┌─────────────────────────────────────────────────┐
│  Approach 1: DIRECT ResponseEntity             │
│  (Without custom wrapper)                      │
├─────────────────────────────────────────────────┤
│  @GetMapping                                   │
│  public ResponseEntity<Product> get() {        │
│      return ResponseEntity.ok(product);        │
│  }                                             │
│                                                │
│  Response: { "id": 1, "name": "..." }         │
│  (Direct object, no wrapper)                  │
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│  Approach 2: CUSTOM ApiResponse Wrapper        │
│  (Industry standard - sabse zyada use hota)   │
├─────────────────────────────────────────────────┤
│  @GetMapping                                   │
│  public ResponseEntity<ApiResponse<Product>>   │
│  get() {                                       │
│      return ResponseEntity.ok(                 │
│          ApiResponse.success(product)          │
│      );                                        │
│  }                                             │
│                                                │
│  Response:                                     │
│  {                                             │
│    "success": true,                           │
│    "data": { "id": 1, "name": "..." },        │
│    "timestamp": 1709388000                    │
│  }                                             │
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│  Approach 3: Spring HATEOAS                    │
│  (Advanced, REST maturity level 3)            │
├─────────────────────────────────────────────────┤
│  Dependency add karo:                          │
│  spring-boot-starter-hateoas                  │
│                                                │
│  EntityModel, CollectionModel use karo        │
│  (But complex hai, rarely use hota)           │
└─────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Folder Structure Mein Kyu Nahi Dikha?

Because YOU have to CREATE it!

src/main/java/com/company/ecommerce/
│
├── dto/
│   ├── request/              ← Ye bhi khud banana
│   │   ├── OrderRequest.java
│   │   └── ProductRequest.java
│   │
│   └── response/             ← YE BHI KHUD BANANA
│       ├── ApiResponse.java     ← ❌ Inbuilt nahi
│       ├── PageResponse.java    ← ❌ Inbuilt nahi
│       ├── ErrorResponse.java   ← ❌ Inbuilt nahi
│       ├── OrderResponse.java
│       └── ProductResponse.java
Enter fullscreen mode Exit fullscreen mode

Real Industry Examples

Example 1: Without ApiResponse (Simple)

@RestController
@RequestMapping("/api/products")
public class ProductController {

    @GetMapping("/{id}")
    public ResponseEntity<Product> getProduct(@PathVariable Long id) {
        Product product = productService.findById(id);
        return ResponseEntity.ok(product);
    }
}

// Response from API:
{
  "id": 1,
  "name": "Laptop",
  "price": 50000
}

// Problem: 
// - Success/failure kaise pata chalega?
// - Error message kahan bhejoge?
// - Metadata (timestamp, etc) kahan?
Enter fullscreen mode Exit fullscreen mode

Example 2: With Custom ApiResponse (Industry Standard)

@RestController
@RequestMapping("/api/products")
public class ProductController {

    @GetMapping("/{id}")
    public ResponseEntity<ApiResponse<Product>> getProduct(@PathVariable Long id) {
        Product product = productService.findById(id);
        return ResponseEntity.ok(ApiResponse.success(product));
    }
}

// Response from API:
{
  "success": true,
  "data": {
    "id": 1,
    "name": "Laptop",
    "price": 50000
  },
  "timestamp": 1709388000000
}

// Benefits:
// ✅ Success clearly indicated
// ✅ Consistent format across all APIs
// ✅ Easy to add metadata
// ✅ Frontend parsing easier
Enter fullscreen mode Exit fullscreen mode

Spring Boot Kya Provide Karta Hai?

Spring Boot Inbuilt Classes:

// 1. ResponseEntity (Inbuilt)
import org.springframework.http.ResponseEntity;

ResponseEntity<Product> response = ResponseEntity.ok(product);
ResponseEntity.status(HttpStatus.CREATED).body(product);
ResponseEntity.notFound().build();

// 2. HttpStatus (Inbuilt)
import org.springframework.http.HttpStatus;

HttpStatus.OK           // 200
HttpStatus.CREATED      // 201
HttpStatus.NOT_FOUND    // 404

// 3. Page (Spring Data - for pagination)
import org.springframework.data.domain.Page;

Page<Product> products = productRepository.findAll(pageable);
// But ye repository level hai, response wrapper nahi

// 4. EntityModel (HATEOAS - advanced)
import org.springframework.hateoas.EntityModel;

EntityModel<Product> resource = EntityModel.of(product);
// But bohot complex hai, rarely use hota
Enter fullscreen mode Exit fullscreen mode

Kya Banana Padega vs Kya Inbuilt Hai

✅ Inbuilt (Spring Boot provides):

Class Package Use
ResponseEntity org.springframework.http HTTP response control
HttpStatus org.springframework.http Status codes
HttpHeaders org.springframework.http Headers
Page org.springframework.data.domain Pagination (repo level)
Pageable org.springframework.data.domain Pagination params

❌ Khud Banana Padega:

Class Purpose Industry Use
ApiResponse Standard wrapper 90% companies
PageResponse Paginated wrapper 90% companies
ErrorResponse Error format 80% companies
OrderRequest/Response Domain DTOs 100% companies

Why Create ApiResponse? Real Reasons

Reason 1: Consistency

// Without ApiResponse - Inconsistent
@GetMapping("/products")
public List<Product> getAll() { ... }
// Returns: [{"id": 1}, {"id": 2}]

@PostMapping("/products")
public Product create() { ... }
// Returns: {"id": 1, "name": "..."}

@GetMapping("/error")
public String error() { ... }
// Returns: "Error message"

// ❌ Different formats confuse frontend
Enter fullscreen mode Exit fullscreen mode
// With ApiResponse - Consistent
@GetMapping("/products")
public ResponseEntity<ApiResponse<List<Product>>> getAll() {
    return ResponseEntity.ok(ApiResponse.success(products));
}
// Returns: {"success": true, "data": [...]}

@PostMapping("/products")
public ResponseEntity<ApiResponse<Product>> create() {
    return ResponseEntity.ok(ApiResponse.success(product));
}
// Returns: {"success": true, "data": {...}}

// ✅ Always same format
Enter fullscreen mode Exit fullscreen mode

Reason 2: Error Handling

// GlobalExceptionHandler
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ApiResponse<Void>> handleNotFound(
            ResourceNotFoundException ex
    ) {
        return ResponseEntity
                .status(HttpStatus.NOT_FOUND)
                .body(ApiResponse.error(ex.getMessage()));
    }
}

// Error Response (consistent):
{
  "success": false,
  "message": "Product not found",
  "timestamp": 1709388000000
}
Enter fullscreen mode Exit fullscreen mode

Companies Kis Tarah Se Use Karte Hain

Startup/Small Company:

// Simple approach - direct ResponseEntity
@GetMapping
public ResponseEntity<List<Product>> getProducts() {
    return ResponseEntity.ok(productService.findAll());
}
Enter fullscreen mode Exit fullscreen mode

Medium/Large Company:

// Standard ApiResponse wrapper
@GetMapping
public ResponseEntity<ApiResponse<List<ProductResponse>>> getProducts() {
    List<Product> products = productService.findAll();
    List<ProductResponse> responses = productMapper.toResponseList(products);
    return ResponseEntity.ok(ApiResponse.success(responses));
}
Enter fullscreen mode Exit fullscreen mode

Enterprise (Amazon, Flipkart level):

// Custom complex wrapper with metadata
@GetMapping
public ResponseEntity<StandardResponse<PagedResult<ProductDTO>>> getProducts(
        Pageable pageable
) {
    PagedResult<ProductDTO> result = productService.getProducts(pageable);

    return ResponseEntity.ok(
        StandardResponse.<PagedResult<ProductDTO>>builder()
            .status("SUCCESS")
            .code(200)
            .data(result)
            .metadata(Metadata.builder()
                .timestamp(Instant.now())
                .requestId(UUID.randomUUID().toString())
                .version("v1")
                .build())
            .build()
    );
}

// Response:
{
  "status": "SUCCESS",
  "code": 200,
  "data": {
    "content": [...],
    "page": 0,
    "totalPages": 10
  },
  "metadata": {
    "timestamp": "2024-02-02T10:30:00Z",
    "requestId": "abc-123-xyz",
    "version": "v1"
  }
}
Enter fullscreen mode Exit fullscreen mode

Final Answer - Ek Baar Mein:

❌ ApiResponse Spring Boot mein INBUILT NAHI hai

✅ Ye aapko KHUD banana padta hai

✅ 90% companies yeh approach follow karti hain

✅ Consistency aur better error handling ke liye

✅ Folder structure mein isliye nahi dikha kyunki 
   aapne abhi tak banaya nahi

✅ Ye ek STANDARD PRACTICE hai, requirement nahi
Enter fullscreen mode Exit fullscreen mode

Quick Action - Abhi Kya Karo?

# 1. Create file
src/main/java/com/yourcompany/dto/response/ApiResponse.java

# 2. Copy-paste the code I gave
# 3. Start using in controllers
# 4. Add GlobalExceptionHandler for errors
Enter fullscreen mode Exit fullscreen mode

That's it! Ab samajh aa gaya? 🚀

Top comments (0)