Building RESTful APIs the Right Way in ASP.NET Core


APIs are the backbone of most modern web and mobile apps, and ASP.NET Core makes building them a breeze. But doing it right means thinking beyond just returning data.
In this post, we’ll walk through building clean, RESTful APIs with ASP.NET Core that follow best practices and avoid common pitfalls.
🛠️ Project Setup
If you don’t already have a project:
dotnet new webapi -n MyApiApp
cd MyApiApp
🧭 Creating Your Controller
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private static List<Product> _products = new();
[HttpGet]
public IActionResult GetAll() => Ok(_products);
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var product = _products.FirstOrDefault(p => p.Id == id);
if (product is null) return NotFound();
return Ok(product);
}
[HttpPost]
public IActionResult Create(Product product)
{
product.Id = _products.Count + 1;
_products.Add(product);
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
}
📦 The Model
public class Product
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public decimal Price { get; set; }
}
✅ ASP.NET Core automatically validates model properties like [Required]
.
🛡️ Model Validation
If your model is invalid, ApiController
will return a 400 Bad Request
with details — no extra code needed.
You can check explicitly like this:
if (!ModelState.IsValid)
return BadRequest(ModelState);
But often it’s not even necessary.
🔁 Returning the Right HTTP Status Codes
200 OK
– when data is successfully returned201 Created
– when you create a resource204 No Content
– when you successfully delete or update without returning content400 Bad Request
– when validation fails404 Not Found
– when a resource doesn't exist
Let your API speak clearly and predictably.
🧪 Swagger for Free
ASP.NET Core comes with Swagger UI out of the box.
- Add this to
Program.cs
(if not already there):
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
app.UseSwagger();
app.UseSwaggerUI();
Now hit https://localhost:5001/swagger
to test your API visually!
🧼 Bonus: Use DTOs for Clean APIs
Avoid returning full database models. Use DTOs (Data Transfer Objects):
public class ProductDto
{
public string Name { get; set; }
public decimal Price { get; set; }
}
It helps keep internal logic decoupled from API responses.
✅ Up Next
Now that you can build clean APIs, let’s talk about data persistence with Entity Framework Core — code-first, migrations, relationships, and more.
➡️ Entity Framework Core Deep Dive →
Let’s move from “working” to wow 🚀
Subscribe to my newsletter
Read articles from Esanju Babatunde directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
