C# tutorials > Frameworks and Libraries > ASP.NET Core > Building RESTful APIs with ASP.NET Core Web API (controllers, routing, response codes)
Building RESTful APIs with ASP.NET Core Web API (controllers, routing, response codes)
This tutorial provides a comprehensive guide on building RESTful APIs using ASP.NET Core Web API. It covers creating controllers, defining routes, and managing HTTP response codes effectively.
Setting up a new ASP.NET Core Web API project
To begin, create a new ASP.NET Core Web API project using the .NET CLI. Open your terminal or command prompt and run the command above. This command scaffolds a basic Web API project with pre-configured files and dependencies.
dotnet new webapi -n MyWebApi
Creating a Controller
This code defines a `ProductsController` which inherits from `ControllerBase`. The `[ApiController]` attribute indicates that this is a Web API controller. The `[Route("[controller]")]` attribute defines the route template. The `Get`, `Get(int id)`, `Post`, `Put`, and `Delete` methods define different API endpoints, handling GET, POST, PUT, and DELETE requests respectively. The IActionResult return type enables returning different HTTP status codes (e.g., Ok, NotFound, CreatedAtAction).
// Controllers/ProductsController.cs
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
namespace MyWebApi.Controllers
{
[ApiController]
[Route("[controller]")]
public class ProductsController : ControllerBase
{
private static readonly List<Product> _products = new List<Product>()
{
new Product { Id = 1, Name = "Product 1", Price = 10.00M },
new Product { Id = 2, Name = "Product 2", Price = 20.00M }
};
[HttpGet]
public ActionResult<IEnumerable<Product>> Get()
{
return _products;
}
[HttpGet("{id}")]
public ActionResult<Product> Get(int id)
{
var product = _products.FirstOrDefault(p => p.Id == id);
if (product == null)
{
return NotFound();
}
return product;
}
[HttpPost]
public ActionResult<Product> Post([FromBody] Product newProduct)
{
if (newProduct == null) {
return BadRequest("Product cannot be null");
}
newProduct.Id = _products.Count > 0 ? _products.Max(p => p.Id) + 1 : 1;
_products.Add(newProduct);
return CreatedAtAction(nameof(Get), new { id = newProduct.Id }, newProduct);
}
[HttpPut("{id}")]
public IActionResult Put(int id, [FromBody] Product updatedProduct)
{
if (updatedProduct == null || id != updatedProduct.Id) {
return BadRequest("Invalid product data");
}
var existingProduct = _products.FirstOrDefault(p => p.Id == id);
if (existingProduct == null) {
return NotFound();
}
existingProduct.Name = updatedProduct.Name;
existingProduct.Price = updatedProduct.Price;
return NoContent(); // 204 No Content - successful update
}
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
var product = _products.FirstOrDefault(p => p.Id == id);
if (product == null)
{
return NotFound();
}
_products.Remove(product);
return NoContent();
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
Understanding Routing
Routing is the process of mapping incoming HTTP requests to the appropriate controller action. ASP.NET Core Web API uses attribute routing, allowing you to define routes directly on your controller actions using attributes like `[HttpGet]`, `[HttpPost]`, `[HttpPut]`, `[HttpDelete]`, and `[Route]`. Route parameters (e.g., `{id}`) are extracted from the URL and passed as arguments to the action method.
Response Codes
HTTP response codes are crucial for communicating the status of API requests to clients. Here's a breakdown of commonly used response codes: * **200 OK:** The request was successful. * **201 Created:** A new resource was successfully created. * **204 No Content:** The request was successful, but there is no content to return. * **400 Bad Request:** The request was invalid. * **401 Unauthorized:** The client is not authenticated. * **403 Forbidden:** The client does not have permission to access the resource. * **404 Not Found:** The resource could not be found. * **500 Internal Server Error:** An unexpected error occurred on the server.
Returning Appropriate Response Codes
Use `IActionResult` to return different HTTP status codes and payloads. For example: * `Ok(result)`: Returns a 200 OK response with the result. * `CreatedAtAction(actionName, routeValues, value)`: Returns a 201 Created response with the location of the newly created resource. * `NotFound()`: Returns a 404 Not Found response. * `BadRequest(errorMessage)`: Returns a 400 Bad Request response with an error message. * `NoContent()`: Returns a 204 No Content response.
Real-Life Use Case
Consider an e-commerce application. The ProductsController manages products, allowing clients to retrieve product details, create new products, update existing products, and delete products. The API endpoints would handle requests from the client-side application (e.g., a React or Angular application) to perform these operations.
Best Practices
Interview Tip
Be prepared to discuss the different HTTP methods (GET, POST, PUT, DELETE) and their corresponding actions (retrieve, create, update, delete). Also, be able to explain the importance of RESTful principles and how ASP.NET Core Web API helps implement them. Know the difference between `IActionResult` and `ActionResult
When to use them
Use ASP.NET Core Web API when you need to build a service that exposes data and functionality over HTTP. It's well-suited for building APIs for web applications, mobile apps, and other services. Choose it when you need a fast, scalable, and cross-platform solution.
Alternatives
Pros
Cons
FAQ
-
What is the difference between `IActionResult` and `ActionResult
`?
`IActionResult` allows you to return any type of HTTP response (e.g., Ok, NotFound, BadRequest). `ActionResult` allows you to return a specific type `T` or an `IActionResult`. `ActionResult ` provides compile-time checking and helps prevent returning unexpected data types. -
How do I handle errors globally in ASP.NET Core Web API?
Use middleware to catch exceptions and return standardized error responses. Create a custom exception handler middleware that intercepts unhandled exceptions and logs them appropriately. It can then return a JSON response with a consistent error format and appropriate HTTP status code (e.g., 500 Internal Server Error).