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)