Hey there! 👋 Are you tired of messy code shit architectures? Well, let’s fix that! In this post, we’ll walk through creating a RESTful API using Clean Architecture with .NET 8. By the end, you’ll have a modular, scalable, and super clean API, which means less stress for you and more time to enjoy your coffee ☕. Let’s dive in!
Wtf is clean architecture ?
You might be wondering, "Why should I bother with Clean Architecture? Isn’t my code already fine?" 🤔 Well, no, your code is bad, but its not important, mine is not better. Clean Architecture helps separate concerns into distinct layers, making your code more maintainable, testable, and future-proof. Plus, it gives you that “I’ve got everything under control” feeling. 😉
Clean Architecture is like a neat apartment: when it’s organized, you can find anything easily. When it’s messy? You end up searching for your keys for 20 minutes (we've all been there 🙈).
The Layers of Clean Architecture
Here’s a quick rundown of the layers in Clean Architecture:
- Core: Where the magic happens – your entities and interfaces.
- Application: This layer handles business logic (services, use cases), talking to Core through interfaces.
- Infrastructure: The concrete stuff – think databases, third-party APIs, and services.
- WebApi: The shiny API layer that interacts with the outside world (a.k.a. your clients).
Steps to Create the API 🚧
lets code !
Creating the Project
First, let’s start by setting up the foundation (i.e. the cool house we’re building 🏠). Open up a terminal and create the projects:
dotnet new sln -n MyCleanApi
dotnet new classlib -n MyCleanApi.Core
dotnet new classlib -n MyCleanApi.Application
dotnet new classlib -n MyCleanApi.Infrastructure
dotnet new webapi -n MyCleanApi.WebApi
dotnet sln MyCleanApi.sln add MyCleanApi.Core/MyCleanApi.Core.csproj
dotnet sln MyCleanApi.sln add MyCleanApi.Application/MyCleanApi.Application.csproj
dotnet sln MyCleanApi.sln add MyCleanApi.Infrastructure/MyCleanApi.Infrastructure.csproj
dotnet sln MyCleanApi.sln add MyCleanApi.WebApi/MyCleanApi.WebApi.csproj
This will create four projects:
- Core: The brains 💡 of your app (entities and interfaces).
- Application: Where the business logic happens (the magic ✨).
- Infrastructure: The hands-on stuff (database, external APIs).
- WebApi: The gateway to your API (like the doorman at a fancy restaurant 🏙️).
Define the Entities (Core) 🏢
In Core, define a simple Product entity (because who doesn’t love products, right? 😄).
namespace MyCleanApi.Core.Entities
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
Define Repository Interfaces (Core) 📚
In Core, define the repository interface to manage your Products. This will act like the API to interact with your data.
namespace MyCleanApi.Core.Interfaces
{
public interface IProductRepository
{
Task<IEnumerable<Product>> GetAllAsync();
Task<Product> GetByIdAsync(int id);
Task AddAsync(Product product);
Task UpdateAsync(Product product);
Task DeleteAsync(int id);
}
}
Create the Services (Application) 💼
In Application, create the service that will handle your business logic. This is the brains behind the operation. No stress, it’s like a superhero team!
namespace MyCleanApi.Application.Services
{
public class ProductService
{
private readonly IProductRepository _productRepository;
public ProductService(IProductRepository productRepository)
{
_productRepository = productRepository;
}
public async Task<IEnumerable<Product>> GetAllProductsAsync()
{
return await _productRepository.GetAllAsync();
}
public async Task<Product> GetProductByIdAsync(int id)
{
return await _productRepository.GetByIdAsync(id);
}
public async Task AddProductAsync(Product product)
{
await _productRepository.AddAsync(product);
}
public async Task UpdateProductAsync(Product product)
{
await _productRepository.UpdateAsync(product);
}
public async Task DeleteProductAsync(int id)
{
await _productRepository.DeleteAsync(id);
}
}
}
Implement the Repository (Infrastructure) 🔧
In Infrastructure, implement the repository using Entity Framework (because EF is like the trusty sidekick of your app 🦸♂️).
namespace MyCleanApi.Infrastructure.Repositories
{
public class ProductRepository : IProductRepository
{
private readonly AppDbContext _context;
public ProductRepository(AppDbContext context)
{
_context = context;
}
public async Task<IEnumerable<Product>> GetAllAsync()
{
return await _context.Products.ToListAsync();
}
public async Task<Product> GetByIdAsync(int id)
{
return await _context.Products.FindAsync(id);
}
public async Task AddAsync(Product product)
{
await _context.Products.AddAsync(product);
await _context.SaveChangesAsync();
}
public async Task UpdateAsync(Product product)
{
_context.Products.Update(product);
await _context.SaveChangesAsync();
}
public async Task DeleteAsync(int id)
{
var product = await _context.Products.FindAsync(id);
if (product != null)
{
_context.Products.Remove(product);
await _context.SaveChangesAsync();
}
}
}
}
Set Up the Database Context (Infrastructure) 🏗️
Now, let’s make sure the database can handle the Products we’re going to throw at it (it’s tough, don’t worry 😆).
namespace MyCleanApi.Infrastructure
{
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
}
}
Set Up Dependency Injection (WebApi) 🤖
In WebApi, we need to configure dependency injection so everything talks to each other (because even APIs need friends 🫶).
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddScoped<IProductRepository, ProductRepository>();
builder.Services.AddScoped<ProductService>();
Create the API Endpoints (WebApi) 📡
Now, let’s expose the API! This is where you handle HTTP requests. We’ll set up the basic CRUD operations for Product.
namespace MyCleanApi.WebApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
private readonly ProductService _productService;
public ProductController(ProductService productService)
{
_productService = productService;
}
[HttpGet]
public async Task<IActionResult> GetAll()
{
var products = await _productService.GetAllProductsAsync();
return Ok(products);
}
[HttpGet("{id}")]
public async Task<IActionResult> GetById(int id)
{
var product = await _productService.GetProductByIdAsync(id);
if (product == null) return NotFound();
return Ok(product);
}
[HttpPost]
public async Task<IActionResult> Create([FromBody] Product product)
{
await _productService.AddProductAsync(product);
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
[HttpPut("{id}")]
public async Task<IActionResult> Update(int id, [FromBody] Product product)
{
product.Id = id;
await _productService.UpdateProductAsync(product);
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
await _productService.DeleteProductAsync(id);
return NoContent();
}
}
}
Testing and Running the API 🎯
Don’t forget to test everything! You can use Postman or any HTTP client to test your API. And remember: always check your database (it’s like checking if your fridge is full before cooking 😅).
Conclusion 🎉
Boom! You’ve now built a RESTful API with .NET and Clean Architecture. Your code is organized, scalable, and ready for future upgrades (like adding a robot army… just kidding… or not 🤖).
Let me know how it goes, or if you have any questions. Happy coding, and may your API requests always return 200 OK! 💻✨
Top comments (0)