Receber por email
← Voltar para o catálogo

dotnet-minimal-api-endpoints

Generates Minimal API endpoints following Microsoft's recommended approach. Creates fast, testable HTTP APIs with minimal code using MapGet/MapPost/MapPut/MapDelete. Preferred over controller-based APIs for new projects.

66estrelas
Atualizado há 5 meses

Ver no GitHub ↗

Como adicionar

/plugin marketplace add ronnythedev/dotnet-clean-architecture-skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/dotnet-minimal-api-endpoints/svg)](https://www.skillteca.com.br/skills/dotnet-minimal-api-endpoints)

Skills relacionadas

Ver todas de Desenvolvimento →

Alerta por categoria

Receba novas skills de Desenvolvimento toda segunda

1 email curto, só com as skills novas de Desenvolvimento. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Minimal API Endpoints Generator

Overview

Microsoft's recommended approach for new projects. Minimal APIs provide a simplified, high-performance way to build HTTP APIs with less boilerplate than controllers.

Benefits Over Controllers

  • ✅ Simpler syntax - Less code, more productivity
  • ✅ Better performance - Reduced overhead
  • ✅ Easier testing - Testable handler methods
  • ✅ Modern approach - Latest .NET features
  • ✅ Less ceremony - No controller classes needed

Quick Reference

| HTTP Method | Extension Method | Use Case | |-------------|------------------|----------| | MapGet | Read single/list | app.MapGet("/users/{id}", ...) | | MapPost | Create | app.MapPost("/users", ...) | | MapPut | Update (full) | app.MapPut("/users/{id}", ...) | | MapDelete | Delete | app.MapDelete("/users/{id}", ...) |

Endpoint Structure

/API/Endpoints/
├── {Feature}/
│   ├── {Feature}Endpoints.cs
│   └── Request{Action}{Entity}.cs
└── ...

Template: Complete CRUD Endpoints

// src/{name}.api/Endpoints/{Feature}/{Feature}Endpoints.cs
using {name}.application.{feature}.Create{Entity};
using {name}.application.{feature}.Delete{Entity};
using {name}.application.{feature}.Get{Entity}ById;
using {name}.application.{feature}.Get{Entities};
using {name}.application.{feature}.Update{Entity};
using {name}.infrastructure.authorization;
using MediatR;
using Microsoft.AspNetCore.Http.HttpResults;

namespace {name}.api.Endpoints.{Feature};

/// <summary>
/// Endpoints for {Entity} management
/// </summary>
public static class {Feature}Endpoints
{
    /// <summary>
    /// Maps all {Entity} endpoints
    /// </summary>
    public static RouteGroupBuilder Map{Feature}Endpoints(this IEndpointRouteBuilder routes)
    {
        var group = routes.MapGroup("/api/{entities}")
            .WithTags("{Feature}")
            .RequireAuthorization();

        group.MapGet("/{id:guid}", GetById)
            .WithName("Get{Entity}ById")
            .WithSummary("Get {entity} by ID")
            .Produces<{Entity}Response>(StatusCodes.Status200OK)
            .Produces(StatusCodes.Status404NotFound);

        group.MapGet("/", GetAll)
            .WithName("GetAll{Entities}")
            .WithSummary("Get all {entities}")
            .Produces<IReadOnlyList<{Entity}ListResponse>>(StatusCodes.Status200OK);

        group.MapPost("/", Create)
            .WithName("Create{Entity}")
            .WithSummary("Create new {entity}")
            .RequireAuthorization(Permissions.{Entities}Write)
            .Produces<Guid>(StatusCodes.Status201Created)
            .Produces(StatusCodes.Status400BadRequest);

        group.MapPut("/{id:guid}", Update)
            .WithName("Update{Entity}")
            .WithSummary("Update existing {entity}")
            .RequireAuthorization(Permissions.{Entities}Write)
            .Produces(StatusCodes.Status204NoContent)
            .Produces(StatusCodes.Status404NotFound)
            .Produces(StatusCodes.Status400BadRequest);

        group.MapDelete("/{id:guid}", Delete)
            .WithName("Delete{Entity}")
            .WithSummary("Delete {entity}")
            .RequireAuthorization(Permissions.{Entities}Write)
            .Produces(StatusCodes.Status204NoContent)
            .Produces(StatusCodes.Status404NotFound);

        return group;
    }

    // ═══════════════════════════════════════════════════════════════
    // HANDLER METHODS
    // ═══════════════════════════════════════════════════════════════

    /// <summary>
    /// Gets an {entity} by ID
    /// </summary>
    private static async Task<Results<Ok<{Entity}Response>, NotFound>> GetById(
        Guid id,
        ISender sender,
        CancellationToken cancellationToken)
    {
        var query = new Get{Entity}ByIdQuery(id);
        var result = await sender.Send(query, cancellationToken);

        return result.IsSuccess
            ? TypedResults.Ok(result.Value)
            : TypedResults.NotFound();
    }

    /// <summary>
    /// Gets all {entities}
    /// </summary>
    private static async Task<Ok<IReadOnlyList<{Entity}ListResponse>>> GetAll(
        ISender sender,
        CancellationToken cancellationToken)
    {
        var query = new GetAll{Entities}Query();
        var result = await sender.Send(query, cancellationToken);

        return TypedResults.Ok(result.Value);
    }

    /// <summary>
    /// Creates a new {entity}
    /// </summary>
    private static async Task<Results<Created<Guid>, BadRequest<Error>>> Create(
        RequestCreate{Entity} request,
        ISender sender,
        CancellationToken cancellationToken)
    {
        var command = new Create{Entity}Command(
            request.Name,
            request.Description);

        var result = await sender.Send(command, cancellationToken);

        return result.IsSuccess
            ? TypedResults.Created($"/api/{entities}/{result.Value}", result.Value)
            : TypedResults.BadRequest(result.Error);
    }

    /// <summary>
    /// Updates an existing {entity}
    /// </summary>
    private static async Task<Results<NoContent, NotFound, BadRequest<Error>>> Update(
        Guid id,
        RequestUpdate{Entity} request,
        ISender sender,
        CancellationToken cancellationToken)
    {
        var command = new Update{Entity}Command(id, request.Name, request.Description);
        var result = await sender.Send(command, cancellationToken);

        if (result.IsFailure)
        {
            return result.Error.Code.Contains("NotFound")
                ? TypedResults.NotFound()
                : TypedResults.BadRequest(result.Error);
        }

        return TypedResults.NoContent();
    }

    /// <summary>
    /// Deletes an {entity}
    /// </summary>
    private static async Task<Results<NoContent, NotFound>> Delete(
        Guid id,
        ISender sender,
        CancellationToken cancellationToken)
    {
        var command = new Delete{Entity}Command(id);
        var result = await sender.Send(command, cancellationToken);

        return result.IsSuccess
            ? TypedResults.NoContent()
            : TypedResults.NotFound();
    }
}

Template: Request DTOs

// src/{name}.api/Endpoints/{Feature}/RequestCreate{Entity}.cs
namespace {name}.api.Endpoints.{Feature};

/// <summary>
/// Request to create a new {entity}
/// </summary>
public sealed record RequestCreate{Entity}(
    string Name,
    string? Description);

/// <summary>
/// Request to update an existing {entity}
/// </summary>
public sealed record RequestUpdate{Entity}(
    string Name,
    string? Description);

Template: Program.cs Registration

// src/{name}.api/Program.cs
using {name}.api.Endpoints.{Feature};
using {name}.application;
using {name}.infrastructure;

var builder = WebApplication.CreateBuilder(args);

// Add services
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddApplication();
builder.Services.AddInfrastructure(builder.Configuration);

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();

// Map endpoints
app.Map{Feature}Endpoints();
// Add more endpoint groups here

app.Run();

Template: Complex Endpoints with MapGroup

// src/{name}.api/Endpoints/{Feature}/{Feature}Endpoints.cs
public static class {Feature}Endpoints
{
    public static RouteGroupBuilder Map{Feature}Endpoints(this IEndpointRouteBuilder routes)
    {
        var group = routes.MapGroup("/api/{entities}")
            .WithTags("{Feature}")
            .RequireAuthorization();

        // Standard CRUD
        group.MapGet("/{id:guid}", GetById);
        group.MapGet("/", GetAll);
        group.MapPost("/", Create);
        group.MapPut("/{id:guid}", Update);
        group.MapDelete("/{id:guid}", Delete);

Compartilhar X LinkedIn