8. Reading Data (GET)

  1. Reading Data (GET)

About this chapter

Implement safe, efficient GET endpoints to retrieve data from your API using query parameters, route parameters, and proper HTTP status codes.

  • Simple GET endpoints: Retrieving collections with pagination
  • GET by ID: Route parameters and named routes
  • HTTP status codes: 200 OK, 404 NotFound responses
  • Query parameters: Filtering, sorting, and pagination options
  • DTOs in responses: Shaping data for clients
  • Error handling: Handling missing resources gracefully

Learning outcomes:

  • Create paginated GET endpoints for collections
  • Implement GET by ID with proper 404 handling
  • Use route parameters and query parameters correctly
  • Design DTOs for read operations
  • Return appropriate HTTP status codes
  • Apply AutoMapper for data transformation

8.1 Simple GET Endpoints

[HttpGet]
public async Task<ActionResult<PaginatedList<PlatformReadDto>>> GetPlatforms(    
  int pageIndex = 1,     
  int pageSize = 10)
{    
  var platforms = await _repository.GetPlatformsAsync(pageIndex, pageSize);    
  var platformDtos = _mapper.Map<PaginatedList<PlatformReadDto>>(platforms);    
  return Ok(platformDtos);
}
  • Query Parameters: Passed in URL: /api/platforms?pageIndex=2&pageSize=20
  • Default Values: Provide sensible defaults
  • Return Type: ActionResult for proper OpenAPI documentation

8.2 GET by ID with Route Parameters

[HttpGet("{id}", Name = "GetPlatformById")]
public async Task<ActionResult<PlatformReadDto>> GetPlatformById(int id)
{    
  var platform = await _repository.GetPlatformByIdAsync(id);        
  
  if (platform == null)        
    return NotFound();  // 404        
  
  var platformDto = _mapper.Map<PlatformReadDto>(platform);    
  return Ok(platformDto);  // 200
}
  • Route Parameter: {id} in route maps to int id parameter
  • Naming Routes: Used for CreatedAtRoute() in POST

8.3 Returning 404 NotFound Appropriately

// ❌ Don't return null or throw exception
public async Task<PlatformReadDto> GetPlatform(int id)
{    
  return await _repository.GetPlatformByIdAsync(id);  // Returns null?
}
// ✅ Return proper status code
public async Task<ActionResult<PlatformReadDto>> GetPlatform(int id)
{    
  var platform = await _repository.GetPlatformByIdAsync(id);        
  
  if (platform == null)        
    return NotFound();  // HTTP 404        
  
  return Ok(_mapper.Map<PlatformReadDto>(platform));  // HTTP 200
}
//✅ With custom message
if (platform == null)    
  return NotFound(new { message = $"Platform with ID {id} not found" });

8.4 NEW: ProducesResponseType Attributes

[HttpGet("{id}", Name = "GetPlatformById")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(PlatformReadDto))]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult<PlatformReadDto>> GetPlatformById(int id)
{    
  // Implementation...
}
  • Benefits:
    • Better Swagger documentation
    • Client code generation accuracy
    • Contract documentation
  • Apply to ALL Endpoints: Documents possible responses