ASP.NET Core Web API

Action Return Types (IActionResult)

1 Views Updated 5/4/2026

Action Return Types (IActionResult & ActionResult<T>)

In ASP.NET Core Web API, deciding how your Controller Actions return data strongly impacts how standard HTTP Status codes are sent to your frontend. Furthermore, choosing the correct return type allows Swagger (OpenAPI) to automatically map your API schema for other developers.

1. Specific Type Return

The simplest way to return data is to simply return the raw C# object. ASP.NET Core will automatically serialize the object into JSON and attach an HTTP 200 (OK) status code.

❌ The Problem
[HttpGet("{id}")]
public Product GetProduct(int id)
{
    var product = _db.Products.Find(id);
    if (product == null) {
        // ERROR: We cannot return "NotFound(404)". 
        // We are strictly bound to returning a 'Product' object!
        return null; // Returns HTTP 204 (No Content), which is semantically incorrect.
    }
    return product;
}

2. IActionResult

Using IActionResult allows you to return varying HTTP status codes depending on the business logic execution (e.g., returning a 404 Not Found, 400 Bad Request, or 200 OK).

✅ The Solution
[HttpGet("{id}")]
public IActionResult GetProduct(int id)
{
    var product = _db.Products.Find(id);
    if (product == null) {
        return NotFound(); // Returns HTTP 404
    }
    return Ok(product); // Returns HTTP 200 populated with JSON
}

However, IActionResult has a downside: Swagger cannot inspect this method at compile-time to know what type of data is wrapped inside the Ok(). Swagger will just document this endpoint as "Returns void", which breaks frontend code generators.

3. ActionResult<T> (The Industry Standard)

Introduced in .NET Core 2.1, ActionResult<T> gives us the best of both worlds. We retain the ability to return multiple HTTP status codes, AND Swagger can automatically infer the T type to generate perfect OpenAPI documentation.

[HttpGet("{id}")]
public ActionResult<Product> GetProductSafe(int id)
{
    var product = _db.Products.Find(id);
    
    if (product == null) {
        return NotFound(); // Implicitly converted to ActionResult<T>
    }
    
    // We don't even need to wrap it in Ok(). 
    // Just returning the generic type implicitly wraps it in an Ok() !
    return product; 
}

4. Common HTTP Helper Methods

MethodStatus CodeTypical Use Case
Ok(data)200 OKA GET request successfully found the data.
CreatedAtRoute()201 CreatedA POST request successfully created a new resource (must include a Location URI).
NoContent()204 No ContentA PUT/DELETE request succeeded, but there is no payload to send back.
BadRequest(modelState)400 Bad RequestThe user sent invalid JSON payload or failed model validation.
Unauthorized()401 UnauthorizedThe user lacks a valid JWT Token.
Forbid()403 ForbiddenThe user has a token, but lacks the specific 'Admin' Role to perform the action.
NotFound()404 Not FoundThe requested Database ID does not exist.

5. Interview Mastery

Q: "When would you explicitly use [ProducesResponseType] attributes instead of relying purely on ActionResult<T>?"

Architect Answer: "While ActionResult<T> handles the Happy Path (HTTP 200) documentation for Swagger perfectly, Swagger still does not know what other HTTP status codes the endpoint might throw under failure conditions. By adding [ProducesResponseType(StatusCodes.Status200OK)] alongside [ProducesResponseType(StatusCodes.Status404NotFound)], you explicitly document for frontend developers exactly what errors to handle. This is the cornerstone of generating robust TypeScript proxy clients from OpenAPI specifications."

ASP.NET Core Web API
1. Fundamentals & HTTP
Introduction to ASP.NET Core Web API REST Principles and HTTP Methods Controllers & ControllerBase Routing (Attribute vs Conventional) Action Return Types (IActionResult)
2. Request Handling
Model Binding (FromQuery, FromBody, FromRoute) Dependency Injection (DI) Deep Dive App Settings & The Options Pattern
3. Data Access & Architecture
EF Core Setup in Web API DbContext & Migrations Repository & Unit of Work Pattern Asynchronous Programming (async/await)
4. Data Transfer & Validation
Data Transfer Objects (DTOs) & AutoMapper Model Validation (DataAnnotations) FluentValidation Integration
5. Advanced Concepts
Global Exception Handling Middleware Content Negotiation (JSON vs XML) Pagination & Filtering Advanced Searching & Sorting HATEOAS (Hypermedia) Implementation Output Caching & Response Caching
6. Security & Authorization
Cross-Origin Resource Sharing (CORS) JWT Authentication Setup Access Tokens & Refresh Tokens Workflow Role-Based & Policy-Based Authorization API Key Authentication Rate Limiting & Throttling
7. Documentation & Testing
Swagger & OpenAPI Configuration Customizing API Documentation Unit Testing Controllers (xUnit & Moq) Integration Testing (WebApplicationFactory)
8. Microservices & Deployment
Consuming External APIs (IHttpClientFactory) Health Checks & Diagnostics API Versioning Strategies Deploying APIs (Docker & Azure)