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 🙏