Skip to main content

Action Results - Returning Correct HTTP Responses

Level: Beginner to Intermediate

ℹ️ Where This Fits

Action results decide what the API sends back to the client. After learning controllers and actions, this is the next important step for writing professional Web APIs.

ℹ️ What You'll Learn
  • Action result purpose: Tell client whether request succeeded and what to do next (status code matters!)
  • IActionResult: Return any response type (View, Json, Redirect, error)
  • ActionResult<T>: Generic version, returns data of type T or error (returns Student or BadRequest)
  • Status 200 OK: Request succeeded, returning data (GET student returns student)
  • Status 201 Created: Resource created successfully, include Location header with new URL (POST student)
  • Status 204 No Content: Request succeeded but no data to return (DELETE student, PUT student with no response body)
  • Status 400 Bad Request: Client error (invalid input, missing required field like student name)
  • Status 401 Unauthorized: User not logged in (missing/invalid JWT token)
  • Status 403 Forbidden: User logged in but lacks permission (student trying to access admin report)
  • Status 404 Not Found: Resource doesn't exist (GET /students/999 when 999 doesn't exist)
  • Status 409 Conflict: Data conflict (try to create student with duplicate roll number)
  • Status 500 Server Error: App error, not client's fault (database connection failed, null reference exception)
  • School Management examples: Create student returns 201, Update returns 200, Delete returns 204, Missing student returns 404
  • Common pattern: Always return appropriate status code + clear error message for debugging
  • Problem Details: RFC 7807 format for errors (type, title, status, detail, instance)
  • Common mistakes in API result handling

What is an Action Result?

An action result tells ASP.NET Core what HTTP response to send.

It can control:

  • status code
  • response body
  • headers
  • redirects
  • files
  • error messages

Example:

return Ok(student);

This means:

HTTP 200 OK
Response body contains student data

Why Status Codes Matter

APIs are used by browsers, mobile apps, frontend apps, and other backend systems.

Status codes help clients understand what happened.

Status CodeMeaning
200Request succeeded
201New resource created
204Success, no content returned
400Client sent invalid data
401User is not authenticated
403User is authenticated but not allowed
404Resource not found
500Server error

Good APIs do not always return 200.

Basic IActionResult Example

💻 Try It — Console App
💡 Create a controller action that returns different results.⌥ GitHub
[HttpGet("{id}")]
public IActionResult GetStudent(int id)
{
if (id <= 0)
{
return BadRequest("Student id must be greater than zero.");
}

var student = _studentService.GetStudent(id);

if (student == null)
{
return NotFound();
}

return Ok(student);
}

This one action can return:

ConditionResult
Invalid id400 Bad Request
Student not found404 Not Found
Student found200 OK

Common Result Methods

MethodStatus CodeUse When
Ok(data)200Data was found or operation succeeded
Created(...)201New record was created
CreatedAtAction(...)201New record created and client should know where to fetch it
NoContent()204Operation succeeded but no body is needed
BadRequest(error)400Input is invalid
Unauthorized()401User has not logged in
Forbid()403User logged in but has no permission
NotFound()404Record does not exist
StatusCode(500)500Unexpected server error

Ok

Use Ok when returning successful data.

[HttpGet]
public IActionResult GetStudents()
{
var students = _studentService.GetAllStudents();
return Ok(students);
}

Response:

200 OK

NotFound

Use NotFound when a requested resource does not exist.

[HttpGet("{id}")]
public IActionResult GetStudent(int id)
{
var student = _studentService.GetStudent(id);

if (student == null)
{
return NotFound(new { message = "Student not found." });
}

return Ok(student);
}

Response:

404 Not Found

BadRequest

Use BadRequest when the client sends invalid input.

[HttpGet("{id}")]
public IActionResult GetStudent(int id)
{
if (id <= 0)
{
return BadRequest(new { message = "Invalid student id." });
}

return Ok();
}

Response:

400 Bad Request

CreatedAtAction

When creating a new resource, return 201 Created.

[HttpPost]
public IActionResult CreateStudent(CreateStudentRequest request)
{
var student = _studentService.CreateStudent(request);

return CreatedAtAction(
nameof(GetStudent),
new { id = student.Id },
student);
}

This tells the client:

Student created successfully.
You can fetch it from the GetStudent action.

NoContent

Use NoContent when the operation succeeds but no response body is needed.

[HttpDelete("{id}")]
public IActionResult DeleteStudent(int id)
{
var deleted = _studentService.DeleteStudent(id);

if (!deleted)
{
return NotFound();
}

return NoContent();
}

Response:

204 No Content

This is common for delete and update operations.

IActionResult vs ActionResult<T>

IActionResult is flexible.

public IActionResult GetStudent(int id)

ActionResult<T> is also flexible, but tells readers the success response type.

public ActionResult<StudentDto> GetStudent(int id)

Example:

[HttpGet("{id}")]
public ActionResult<StudentDto> GetStudent(int id)
{
var student = _studentService.GetStudent(id);

if (student == null)
{
return NotFound();
}

return Ok(student);
}

For Web APIs, ActionResult<T> is often clearer.

School API Example

[ApiController]
[Route("api/admissions")]
public class AdmissionsController : ControllerBase
{
private readonly IAdmissionService _admissionService;

public AdmissionsController(IAdmissionService admissionService)
{
_admissionService = admissionService;
}

[HttpPost]
public ActionResult<AdmissionResponse> SubmitApplication(
CreateAdmissionRequest request)
{
if (request.DateOfBirth > DateTime.Today)
{
return BadRequest(new { message = "Date of birth is invalid." });
}

var response = _admissionService.Submit(request);

return CreatedAtAction(
nameof(GetApplication),
new { id = response.Id },
response);
}

[HttpGet("{id}")]
public ActionResult<AdmissionResponse> GetApplication(int id)
{
var application = _admissionService.GetApplication(id);

if (application == null)
{
return NotFound();
}

return Ok(application);
}
}

Common Mistakes

MistakeBetter Approach
Returning Ok() for every situationReturn correct status codes
Returning null when record is missingReturn NotFound()
Returning created data with Ok()Use Created or CreatedAtAction
Throwing exceptions for validation errorsReturn BadRequest or validation response
Returning database entities directlyReturn DTOs
Hiding all errors as 500Use accurate client/server status codes

Practice Task

Create a FeesController.

  1. GET /api/fees/{studentId} returns Ok(fees) when found.
  2. Return BadRequest() when studentId <= 0.
  3. Return NotFound() when no fee record exists.
  4. POST /api/fees/payments returns CreatedAtAction().
  5. DELETE /api/fees/payments/{id} returns NoContent().

Quick Recap

QuestionAnswer
Success with data?Ok(data)
New resource created?CreatedAtAction(...)
Invalid input?BadRequest(...)
Missing record?NotFound()
Success without body?NoContent()
🎯 Interview Favourite

Q: What are action results in ASP.NET Core?

Good Answer: "Action results are return types from controller actions that tell ASP.NET Core what HTTP response to send. They control status code, response body, headers, files, and redirects. Common results include Ok for 200, CreatedAtAction for 201, BadRequest for 400, Unauthorized for 401, Forbid for 403, NotFound for 404, and NoContent for 204. Correct action results make APIs clear and easier for clients to consume."

🤖Use AI to Learn Faster

Use ChatGPT, Claude, or Copilot to go deeper on Action Results. Try these prompts:

  • "Explain IActionResult using a school API example."
  • "When should I return Ok, CreatedAtAction, BadRequest, and NotFound?"
  • "What is the difference between IActionResult and ActionResult<T>?"
  • "Design proper responses for create, update, delete, and get APIs."

💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.

Next Article

-> Model Binding and Validation

nexcoding.in