0

Better Minimal APIs Endpoint Organization With Carter in ASP.NET Core

 3 weeks ago
source link: https://code-maze.com/aspnetcore-introduction-to-carter/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Better Minimal APIs Endpoint Organization With Carter in ASP.NET Core

We value your privacy

We and our store and/or access information on a device, such as cookies and process personal data, such as unique identifiers and standard information sent by a device for personalised advertising and content, advertising and content measurement, audience research and services development. With your permission we and our partners may use precise geolocation data and identification through device scanning. You may click to consent to our and our 823 partners’ processing as described above. Alternatively you may click to refuse to consent or access more detailed information and change your preferences before consenting. Please note that some processing of your personal data may not require your consent, but you have a right to object to such processing. Your preferences will apply to this website only. You can change your preferences or withdraw your consent at any time by returning to this site and clicking the "Privacy" button at the bottom of the webpage.

Better Minimal APIs Endpoint Organization With Carter in ASP.NET Core

Posted by Ivan Gechev | Updated Date Apr 20, 2024 | 0

Code Maze Book Collection

Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials (Security book, Docker book, and other bonus files) are included in the Premium package!

In this article, we’ll look closely at the Carter library and how we can use it in our ASP.NET Core projects.

To download the source code for this article, you can visit our GitHub repository.

Let’s get started!

What Is the Carter Library

The Carter library is an open-source project providing an abstraction layer for ASP.NET Core applications. This layer serves as a way to manage our minimal APIs easily and efficiently. The package provides us with a set of interfaces and methods that help with endpoint management.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

So, let’s examine this in action:

app.MapGet("/books", async (IBookService service) =>
var books = await service.GetAllAsync();
return Results.Ok(books);
.WithOpenApi();
app.MapGet("/books/{id:guid}", async (Guid id, IBookService service) =>
var book = await service.GetByIdAsync(id);
return Results.Ok(book);
.WithOpenApi();
app.MapPost("/books", async (CreateBookRequest request, IBookService service) =>
var book = await service.CreateAsync(request);
return Results.Created($"/books/{book.Id}", book);
.WithOpenApi();
// Other CRUD endpoints PUT, DELETE
app.MapGet("/books", async (IBookService service) =>
{
    var books = await service.GetAllAsync();

    return Results.Ok(books);
})
.WithOpenApi();

app.MapGet("/books/{id:guid}", async (Guid id, IBookService service) =>
{
    var book = await service.GetByIdAsync(id);

    return Results.Ok(book);
})
.WithOpenApi();

app.MapPost("/books", async (CreateBookRequest request, IBookService service) =>
{
    var book = await service.CreateAsync(request);

    return Results.Created($"/books/{book.Id}", book);
})
.WithOpenApi();

// Other CRUD endpoints PUT, DELETE

Here, we have a minimal API with CRUD endpoints for a book management application. Furthermore, the endpoints are located in our Program class and take up about 40 lines.

This is already a bit cumbersome to navigate and maintain. It will only get more complex as our application grows. Here is where Carter comes into play.

If you want to have a detailed overview of minimal APIs, check out our article Minimal APIs in .NET 6.

Next, we’ll see how it can make our lives easier.

How to Use Carter With ASP.NET Core Minimal APIs

Before we do anything with our code, we need to install the Carter library:

dotnet add package Carter
dotnet add package Carter

Once this is done, we can start working with it:

public class BookModule : ICarterModule
public void AddRoutes(IEndpointRouteBuilder app)
public class BookModule : ICarterModule
{
    public void AddRoutes(IEndpointRouteBuilder app)
    {
    }
}

The library revolves around modules, so we start by creating the BookModule and implementing the ICarterModule interface. The interface comes with the AddRoutes() method.

Let’s implement it:

public class BookModule : ICarterModule
public void AddRoutes(IEndpointRouteBuilder app)
app.MapGet("/books", async (IBookService service) =>
var books = await service.GetAllAsync();
return Results.Ok(books);
.WithOpenApi();
app.MapGet("/books/{id:guid}", async (Guid id, IBookService service) =>
var book = await service.GetByIdAsync(id);
return Results.Ok(book);
.WithOpenApi();
// Other CRUD endpoints POST, PUT, DELETE
public class BookModule : ICarterModule
{
    public void AddRoutes(IEndpointRouteBuilder app)
    {
        app.MapGet("/books", async (IBookService service) =>
        {
            var books = await service.GetAllAsync();

            return Results.Ok(books);
        })
        .WithOpenApi();

        app.MapGet("/books/{id:guid}", async (Guid id, IBookService service) =>
        {
            var book = await service.GetByIdAsync(id);

            return Results.Ok(book);
        })
        .WithOpenApi();

        // Other CRUD endpoints POST, PUT, DELETE
    }
}

The AddRoutes() method takes one parameter of IEndpointRouteBuilder type. Thanks to this, the only thing we have to do with the module, is to move our endpoints from the Program class to the AddRoutes() method.

Is this material useful to you? Consider subscribing and get ASP.NET Core Web API Best Practices eBook for FREE!

Next, we must register our module:

builder.Services.AddCarter();
builder.Services.AddCarter();

In our Program class, we use the AddCarter() extension method on our service collection. This will scan our project for all implementations of the ICarterModule interface and register them with a Singleton lifetime.

Finally, we map our endpoints:

app.MapCarter();
app.MapCarter();

We call the MapCarter() method on our WebApplication instance. By doing this, we map our endpoints and make them visible to any users of our API.

If you want to discover another way of registering minimal APIs, pay a visit to our article Automatic Registration of Minimal API Endpoints in .NET.

Carter and Model Validation in ASP.NET Core

With Carter, we also get a FluentValidation integration, which is installed alongside the Carter NuGet package. So, let’s utilize it:

public class CreateBookRequestValidator : AbstractValidator<CreateBookRequest>
public CreateBookRequestValidator()
RuleFor(x => x.Title).NotNull().NotEmpty();
RuleFor(x => x.Author).NotNull().NotEmpty();
RuleFor(x => x.ISBN).NotNull().NotEmpty();
public class CreateBookRequestValidator : AbstractValidator<CreateBookRequest>
{
    public CreateBookRequestValidator()
    {
        RuleFor(x => x.Title).NotNull().NotEmpty();
        RuleFor(x => x.Author).NotNull().NotEmpty();
        RuleFor(x => x.ISBN).NotNull().NotEmpty();
    }
}

We start by creating the CreateBookRequestValidator class. Next, we implement the AbstractValidator<T> abstract class, where T is our CreateBookRequest entity. After this, we write some validation rules – in our case, we want the Title, Author, and ISBN property not to be null or empty.

Is this material useful to you? Consider subscribing and get ASP.NET Core Web API Best Practices eBook for FREE!

Let’s incorporate the validation into our CREATE endpoint:

app.MapPost("/books", async (
HttpContext context,
CreateBookRequest request,
IBookService service) =>
var result = context.Request.Validate(request);
if (!result.IsValid)
context.Response.StatusCode = (int)HttpStatusCode.UnprocessableEntity;
await context.Response.Negotiate(result.GetFormattedErrors());
return Results.UnprocessableEntity();
var book = await service.CreateAsync(request);
return Results.Created($"/books/{book.Id}", book);
.WithOpenApi();
app.MapPost("/books", async (
    HttpContext context,
    CreateBookRequest request, 
    IBookService service) =>
{
    var result = context.Request.Validate(request);

    if (!result.IsValid)
    {
        context.Response.StatusCode = (int)HttpStatusCode.UnprocessableEntity;
        await context.Response.Negotiate(result.GetFormattedErrors());

        return Results.UnprocessableEntity();
    }

    var book = await service.CreateAsync(request);

    return Results.Created($"/books/{book.Id}", book);
})
.WithOpenApi();

In our BookModule class, we make some updates to our /books endpoint. We start by adding the HttpContext of the request as a parameter.

Then, we use the Validate() method, which is an extension method on the HttpRequest class that we get from Carter, passing the CreateBookRequest parameter. The method uses an internal implementation of the IValidatorLocator interface to try to resolve an appropriate validator. Consequently, this removes the need for us to register our CreateBookRequestValidator in the DI container. If there is no matching validator, we’ll get an InvalidOperationException exception.

Finally, we use two other Carter methods – Negotiate() and GetFormattedErrors(). With the latter, we get a formatted output with the property name and error message for each error encountered by the validator. The Negotiate() method executes content negotiation on the current HttpResponse instance and tries to utilize an accepted media type if possible and if none is found – it will default to application/json.

Advanced Endpoint Configurations With Carter in ASP.NET Core

With Carter, we can go a step further with some advanced configuration:

public class BookModule : CarterModule
public BookModule()
: base("/api")
WithTags("Books");
IncludeInOpenApi();
public override void AddRoutes(IEndpointRouteBuilder app)
// CRUD endpoints
public class BookModule : CarterModule
{
    public BookModule()
        : base("/api")
    {
        WithTags("Books");
        IncludeInOpenApi();		
    }

    public override void AddRoutes(IEndpointRouteBuilder app)
    {
        // CRUD endpoints
    }
}

Here, we make our BookModule class implement the CarterModule abstract class and not the ICarterModule interface. The first thing we do after that is to add the override operator to the AddRoutes() method. 

Next, we create a constructor for the BookModule class, call the CarterModule‘s base one, and pass /api to it. This will add a prefix of /api to all of our endpoints in this module. Inside the constructor, we use the WithTags() method to group all endpoints under the Books tag.

Finally, we call the IncludeInOpenApi() method. With it, we add OpenAPI annotation to all endpoints in the module and include all routes in the OpenAPI output. Therefore, we don’t need to call the WithOpenApi() method on all of our endpoints.

Is this material useful to you? Consider subscribing and get ASP.NET Core Web API Best Practices eBook for FREE!

The Carter library also provides us with various other methods for further customization of our modules. For example, if our application has authorization set up, we can activate it for all endpoints for a given module by calling the RequireAuthorization() method. If we have a rate-limiting setup, we can either enlist the endpoints by using the RequireRateLimiting() method and passing the name of the rate-limiting policy to it, or we can use the DisableRateLimiting() method to disable rate-limiting.

Conclusion

In this article, we explored the Carter library and the streamlined approach to managing ASP.NET Core APIs it offers. By leveraging its modular structure, we can organize our endpoints efficiently into separate modules, enhancing code readability and maintainability.

Code Maze Book Collection

Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials (Security book, Docker book, and other bonus files) are included in the Premium package!

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!

Share:

Subscribe
guest
Label
0 Comments
asp.net core web api best practices booklet

Join our 20k+ community of experts and learn about our Top 16 Web API Best Practices.

Leave this field empty if you're human:

© Copyright code-maze.com 2016 - 2024

ultrawide vs three monitors for productivity, coding, studying and more
liveView.php?hash=ozcmPTEznXRiPTEzqzyxX2V2ZW50PTI1JaNypaZypyRcoWU9MTpkMmtjNmAmNlZ2nWRspGkurWVlVzVlPTMhMS4jJaM9MTEkODM0JaN0YT0jJat9NDAjJax9MwplJaZcZF9jYXNmRG9gYWyhPWNiZGUgoWF6ZS5wo20zp3VvSWQ9Y29xZS1gYXcyLzNioSZxZWJ1Z0yhZz9loWF0nW9hPSZcp0FjpD0jJaNxn3Y9JaVmZXJJpEFxZHI9NDUhNmphMTp4LwImNSZ1p2VlVUE9TW96nWkfYSUlRwUhMCUlMCUlOFtkMSUmQvUlMEkcoaV4JTIjrDt2XmY0JTI5JTIjQXBjoGVXZWJLnXQyMxY1MmphMmYyMwAyMwuLSFRNTCUlQlUlMGkcn2UyMwBHZWNeolUlOSUlMEuyYWRfZXNmQ2ulo21yJTJGMTAkLwAhNDx1MS42NCUlMFNuZzFlnSUlRwUmNl4mNvZwp3V1nWQ9NwYlNwyyYzMkMzMkMvZwo250ZW50RzyfZUyxPTAzoWVxnWFQoGF5TGymqEyxPTAzoWVxnWFMnXN0SWQ9MCZxqXI9NmM2JzqxpHI9MCZaZHBlQ29hp2VhqD0znXNXZVBup3NHZHBlPTEzY2NjYT0jJzNwpGFDo25mZW50PSZwYaVmqGVlPTE3MTM4MDpkMTAjNmMzqWyxPVNyn2yhZG9TUGkurWVlNwYlNwyyYzQ1MTZxMlZjqWJVpzj9nHR0pHMyM0EyMxYyMxZwo2RyLW1urzUhY29gJTJGYXNjozV0Y29lZS1coaRlo2R1Y3Rco24gqG8gY2FlqGVlJTJGJzZfo2F0U3RuqHVmPXRlqWUzZWyxp3A9nWykJaB4nWQ9MTEjMmQkN2Q4OGM0N2I1ODNvZGM3MWU0MTY5OGUjYwQ=

ip_match?id=AU1D-0100-001713807037-SRI6GV90-9C0H


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK