4

Carter Community for ASP.NET Core means enjoyable Web APIs on the cutting edge

 2 years ago
source link: https://www.hanselman.com/blog/carter-community-for-aspnet-core-means-enjoyable-web-apis-on-the-cutting-edge
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.
Carter Community for ASP.NET Core means enjoyable Web APIs on the cutting edge
Sponsored By

I blogged about the open source Carter Community Project in 2019. Let's check in and see what's going on today in 2021!

With .NET 6 on the near horizon, one notes that Carter has a net6 branch. Per their website, this is the goal of the Carter framework:

Carter is framework that is a thin layer of extension methods and functionality over ASP.NET Core allowing code to be more explicit and most importantly more enjoyable.

As of today you can bring Carter into your .NET 6 projects like this:

dotnet add package Carter --version 6.0.0-pre2

And the .NET 6 samples are under active development! Let's bring it down with a clone, switch to the net6 branch and give it a go.

Here's as simple Web API sample with Carter that returns a list of actors at localhost:5001/actors

using Carter;
using CarterSample.Features.Actors;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IActorProvider, ActorProvider>();
builder.Services.AddCarter();
var app = builder.Build();
app.MapCarter();
app.Run();

Nice! This is using new .NET 6 features so there's no Main(), it's implied. The builder has an ActorProvider added as a Singleton. I bet we'll use that when we ask for /actors in our browser or favorite HTTP API client.

public class ActorsModule : ICarterModule
{
public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapGet("/actors", (IActorProvider actorProvider, HttpResponse res) =>
{
var people = actorProvider.Get();
return people;
});
...
}
}

This is nice and clean. Everything is using Dependency Injection so no one is "newing up" an Actor. You'll note also that returning the Actors as JSON is implied when we return the IEmumerable<Actor> that comes from actorProvider.Get().

In fact, the whole Actor Module is just 80 lines so I'll include it here:

public class ActorsModule : ICarterModule
{
public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapGet("/actors", (IActorProvider actorProvider, HttpResponse res) =>
{
var people = actorProvider.Get();
return people;
});
app.MapGet("/actors/{id:int}", (int id, IActorProvider actorProvider, HttpResponse res) =>
{
var person = actorProvider.Get(id);
return res.Negotiate(person);
});
app.MapPut("/actors/{id:int}", async (HttpRequest req, Actor actor, HttpResponse res) =>
{
var result = req.Validate<Actor>(actor);
if (!result.IsValid)
{
res.StatusCode = 422;
await res.Negotiate(result.GetFormattedErrors());
return;
}
//Update the user in your database
res.StatusCode = 204;
});
app.MapPost("/actors", async (HttpContext ctx, Actor actor) =>
{
var result = ctx.Request.Validate<Actor>(actor);
if (!result.IsValid)
{
ctx.Response.StatusCode = 422;
await ctx.Response.Negotiate(result.GetFormattedErrors());
return;
}
//Save the user in your database
ctx.Response.StatusCode = 201;
await ctx.Response.Negotiate(actor);
});
app.MapDelete("/actors/{id:int}", (int id, IActorProvider actorProvider, HttpResponse res) =>
{
actorProvider.Delete(id);
return Results.StatusCode(204);
});
app.MapGet("/actors/download", async (HttpResponse response) =>
{
using (var video = new FileStream("earth.mp4", FileMode.Open)) //24406813
{
await response.FromStream(video, "video/mp4");
}
});
app.MapGet("/empty", () => Task.CompletedTask);
app.MapGet("/actors/sample", () => Task.CompletedTask);
app.MapPost("/actors/sample", () => Task.CompletedTask);
app.MapGet("/nullable", () => Task.CompletedTask);
}
}

Note the API example at /actors/download that shows how to return a file like an MP4. Nice and simple. This sample also includes thoughtful validation code with FluentValidation extension methods like ctx.Request.Validate().

Carter is opinionated but surprisingly flexible. You can use two different routing APIs, or clean and performant Endpoint routing:

this.Get("/", (req, res) => res.WriteAsync("There's no place like 127.0.0.1")).RequireAuthorization();

It even supports OpenAPI out of the box! Carter has an active Slack as well as Templates you can add to make your next File | New Project easier!

dotnet new -i CarterTemplate
The following template packages will be installed:
CarterTemplate

Success: CarterTemplate::5.2.0 installed the following templates:
Template Name Short Name Language Tags
--------------- ---------- -------- ------------------------------
Carter Template carter [C#] Carter/Carter Template/NancyFX

There's a lot of great innovation happening in the .NET open source space right now.

Carter Source Code

Carter is just one cool example. Go check out Carter on GitHub, give them a Star, try it out and get involved in open source!


Sponsor: YugabyteDB is a distributed SQL database designed for resilience and scale. It is 100% open source, PostgreSQL-compatible, enterprise-grade, and runs across all clouds. Sign up and get a free t-shirt


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK