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 ?
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 ๐
Yes, no problem, ill make a github repo and come back to you this afternoon ;)