DEV Community

Rafa Eslava
Rafa Eslava

Posted on

🎯 From 50+ Lines to 1 Line: Zero Boilerplate ASP.NET APIs

πŸ“– The Problem: Repetitive API Code
Every .NET developer writes this boilerplate:

// BEFORE: 15+ lines for ONE endpoint
app.MapGet("/api/products/{id}", async (int id, ProductService service) =>
{
    if (id <= 0) return Results.BadRequest("Invalid ID");
    var product = await service.GetProductAsync(id);
    return product == null 
        ? Results.NotFound("Product not found")
        : Results.Ok(product);
});
Enter fullscreen mode Exit fullscreen mode

πŸš€ The Solution: Source Generator Magic
πŸ“¦ Setup:

// Program.cs - One time setup
using REslava.Result.SourceGenerators;
[assembly: GenerateResultExtensions()]
Enter fullscreen mode Exit fullscreen mode

✨ The Magic:

// AFTER: 3 lines total!
app.MapGet("/api/products/{id}", async (int id, ProductService service) =>
    => (await service.GetProductAsync(id)).ToIResult());
Enter fullscreen mode Exit fullscreen mode

That's it! 80% code reduction! 🀯

πŸ” Smart Error Mapping
The generator automatically handles errors:

"not found" β†’ 404
"validation" β†’ 422  
"unauthorized" β†’ 401
"forbidden" β†’ 403
"conflict" β†’ 409
Enter fullscreen mode Exit fullscreen mode

πŸ“Š Real Impact
Operation Before After Reduction
GET 15 lines 3 lines 80%
POST 20 lines 3 lines 85%
PUT 18 lines 3 lines 83%

🎯 Complete API Example

πŸ“‹ BEFORE (50+ lines):

app.MapGet("/api/products", async (ProductService service) =>
{
    try { return Results.Ok(await service.GetAllProductsAsync()); }
    catch { return Results.Problem("Error", statusCode: 500); }
});

app.MapGet("/api/products/{id}", async (int id, ProductService service) =>
{
    if (id <= 0) return Results.BadRequest("Invalid ID");
    var product = await service.GetProductAsync(id);
    return product == null ? Results.NotFound() : Results.Ok(product);
});

app.MapPost("/api/products", async (CreateProductRequest request, ProductService service) =>
{
    if (string.IsNullOrWhiteSpace(request.Name))
        return Results.ValidationProblem(new { Name = new[] { "Required" } });
    var product = await service.CreateProductAsync(request);
    return Results.Created($"/api/products/{product.Id}", product);
});
Enter fullscreen mode Exit fullscreen mode

πŸš€ AFTER (9 lines):

app.MapGet("/api/products", async (ProductService service) =>
    => (await service.GetAllProductsAsync()).ToIResult());

app.MapGet("/api/products/{id}", async (int id, ProductService service) =>
    => (await service.GetProductAsync(id)).ToIResult());

app.MapPost("/api/products", async (CreateProductRequest request, ProductService service) =>
    => (await service.CreateProductAsync(request)).ToPostResult(p => $"/api/products/{p.Id}"));
Enter fullscreen mode Exit fullscreen mode

🎯 HTTP Method Extensions

.ToIResult()        // GET - 200/400/404/500
.ToPostResult()     // POST - 201 Created
.ToPutResult()      // PUT - 200 OK
.ToDeleteResult()   // DELETE - 200 OK
Enter fullscreen mode Exit fullscreen mode

πŸš€ Get Started
πŸ“¦ Install:

dotnet add package REslava.Result
dotnet add package REslava.Result.SourceGenerators
Enter fullscreen mode Exit fullscreen mode

✨ Setup:

using REslava.Result.SourceGenerators;
[assembly: GenerateResultExtensions()]
Enter fullscreen mode Exit fullscreen mode

🎯 Use:

return await service.GetDataAsync().ToIResult();
Enter fullscreen mode Exit fullscreen mode

🌟 Benefits
πŸš€ 80-90% Code Reduction
🧠 Smart Error Handling
πŸ“– RFC 7807 Compliant
⚑ Zero Runtime Overhead
πŸ”§ Compile-Time Generation

πŸŽ‰ Conclusion
Source generators transform .NET API development from repetitive boilerplate to elegant, declarative code.

Try it today and never write manual HTTP responses again! πŸš€

πŸ“š Learn More
πŸ“¦ NuGet Package
πŸ“– Documentation
🌐 Live Samples

GitHub
NuGet

dotnet #csharp #aspnetcore #sourcegenerators #webdev #apidevelopment

Top comments (0)