Skip to content

Latest commit

 

History

History
257 lines (208 loc) · 6.53 KB

File metadata and controls

257 lines (208 loc) · 6.53 KB

API Response Structure Simplification

Overview

This document explains the simplification applied to the CreateOrder endpoint response structure.

What Changed

Before (Nested Structure)

{
  "success": true,
  "message": "Order created and published successfully",
  "data": {
    "model": {
      "id": "19b85ea1-be19-4aa8-a228-bdfaaa49273c",
      "customerName": "Alice T",
      "productName": "Wireless Mouse",
      "quantity": 2,
      "totalAmount": 54545,
      "status": "Created",
      "createdAt": "2025-11-21T19:27:57.6633428Z"
    }
  },
  "errors": null,
  "timestamp": "2025-11-21T19:27:57.6681873Z"
}

Response Type: ApiResponse<CreateResponseDto<OrderResponseDto>>

After (Simplified Structure)

{
  "success": true,
  "message": "Order created and published successfully",
  "data": {
    "id": "19b85ea1-be19-4aa8-a228-bdfaaa49273c",
    "customerName": "Alice T",
    "productName": "Wireless Mouse",
    "quantity": 2,
    "totalAmount": 54545,
    "status": "Created",
    "createdAt": "2025-11-21T19:27:57.6633428Z"
  },
  "errors": null,
  "timestamp": "2025-11-21T19:27:57.6681873Z"
}

Response Type: ApiResponse<OrderResponseDto>

Benefits of Simplification

Flatter Structure

  • Removed unnecessary nesting (data.modeldata)
  • Order properties are now directly accessible
  • Easier to parse and consume by client applications

Improved Client Experience

// Before
const orderId = response.data.model.id;
const customerName = response.data.model.customerName;

// After
const orderId = response.data.id;
const customerName = response.data.customerName;

Consistent with Other Endpoints

  • Other endpoints (payment, shipping, delivery, cancel) already return flat structures
  • All endpoints now follow the same pattern

Reduced Complexity

  • Fewer types to maintain
  • Simpler mapping logic
  • Less cognitive overhead for developers

Better Performance

  • Slightly smaller JSON payload
  • Faster serialization/deserialization

Code Changes

1. Controller Method Signature

// Before
public async Task<ActionResult<ApiResponse<CreateResponseDto<OrderResponseDto>>>> CreateOrder(...)

// After
public async Task<ActionResult<ApiResponse<OrderResponseDto>>> CreateOrder(...)

2. Response Mapping

// Before
var responseData = order.ToCreateResponseDto(); // Returns CreateResponseDto<OrderResponseDto>
var response = ApiResponse<CreateResponseDto<OrderResponseDto>>.SuccessResponse(responseData, "...");

// After
var responseData = order.ToResponseDto(); // Returns OrderResponseDto directly
var response = ApiResponse<OrderResponseDto>.SuccessResponse(responseData, "...");

3. Extension Method Status

// ToCreateResponseDto() marked as obsolete
[Obsolete("This method is no longer used. Use ToResponseDto() directly for a simpler response structure.")]
public static CreateResponseDto<OrderResponseDto> ToCreateResponseDto(this Order order)

Migration Guide for API Consumers

If you're consuming this API from a client application:

JavaScript/TypeScript

// Before
const order = response.data.model;

// After
const order = response.data;

C# Client

// Before
var apiResponse = await client.GetFromJsonAsync<ApiResponse<CreateResponseDto<OrderResponseDto>>>("/api/orders");
var order = apiResponse.Data.Model;

// After
var apiResponse = await client.GetFromJsonAsync<ApiResponse<OrderResponseDto>>("/api/orders");
var order = apiResponse.Data;

Python

# Before
order = response.json()["data"]["model"]

# After
order = response.json()["data"]

When to Use CreateResponseDto

The CreateResponseDto<T> wrapper should be used when you need to return additional creation metadata beyond the created resource itself.

Examples of When to Keep the Wrapper:

Scenario 1: Include Creation Location

public class CreateResponseDto<T>
{
    public T Model { get; set; }
    public string CreatedAtUrl { get; set; }  // e.g., "/api/orders/123"
    public string EventId { get; set; }        // RabbitMQ event ID
}

Scenario 2: Include Processing Status

public class CreateResponseDto<T>
{
    public T Model { get; set; }
    public string QueuePosition { get; set; }
    public TimeSpan EstimatedProcessingTime { get; set; }
}

Scenario 3: Include Related Resources

public class CreateResponseDto<T>
{
    public T Model { get; set; }
    public List<string> RelatedResourceUrls { get; set; }
}

Current Recommendation:

Since we don't have additional metadata to return, the simplified structure is better.

Rollback Instructions

If you need to revert to the nested structure:

// In OrdersController.cs CreateOrder method:

// Replace:
var responseData = order.ToResponseDto();
var response = ApiResponse<OrderResponseDto>.SuccessResponse(responseData, "...");

// With:
var responseData = order.ToCreateResponseDto();
var response = ApiResponse<CreateResponseDto<OrderResponseDto>>.SuccessResponse(responseData, "...");

// And update method signature:
public async Task<ActionResult<ApiResponse<CreateResponseDto<OrderResponseDto>>>> CreateOrder(...)

Testing the Change

Test with Swagger UI

  1. Navigate to http://localhost:8080/swagger (or your configured port)
  2. Test POST /api/orders endpoint
  3. Verify response structure:
    • data should contain order properties directly
    • ✅ No data.model nesting

Test with curl

curl -X POST "http://localhost:8080/api/orders" \
  -H "Content-Type: application/json" \
  -d '{
    "customerName": "John Doe",
    "productName": "Laptop",
    "quantity": 1,
    "totalAmount": 1299.99
  }'

Expected Response:

{
  "success": true,
  "message": "Order created and published successfully",
  "data": {
    "id": "...",
    "customerName": "John Doe",
    "productName": "Laptop",
    "quantity": 1,
    "totalAmount": 1299.99,
    "status": "Created",
    "createdAt": "..."
  },
  "errors": null,
  "timestamp": "..."
}

Summary

The response structure simplification:

  • Removes unnecessary nesting
  • Improves client developer experience
  • Maintains consistency across endpoints
  • Reduces complexity
  • Follows REST best practices

The CreateResponseDto<T> type remains available for future use if additional creation metadata is needed, but is marked as obsolete for current usage.


Document Version: 1.0
Last Updated: 2025-01-21
Author: Dariem Carlos Macias