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 (6)
May you publish your codes to the github ?
Yes, no problem, ill make a github repo and come back to you this afternoon ;)
github.com/mou-inoks/clean-archite...
here, there is a bit more then in this guide.
That deserves more than 10K github stars.πβ€οΈππ
thank you very much for your comments appriciate it
Thank you very much π