A .NET 6 Minimal API Todo instance Playground

[ad_1]


Minimalism from UnsplashI actually like minimal Internet APIs. I’ve appreciated the thought for years. With .NET 6, it is beginning to occur! Damian Edwards has an fascinating minimal API Playground on his GitHub and Maria Naggaga did a nice speak on Minimal APIs in .NET 6 that is up on YouTube!

Let’s discover! I am operating the newest .NET 6 and you may run it on Home windows, Mac, or Linux and I cloned it to a folder regionally.

There’s two variations of an entire Todo API on this pattern, one utilizing Entity Framework Core and one utilizing Dapper for information entry. Each are light-weight ORMs (object relational mappers). Let’s discover the Dapper instance that makes use of SQLite.

The opening of the code on this instance does not require a Essential() which removes a pleasant little bit of traditionally unneeded syntactic sodium. The Essential is implied.

utilizing System.ComponentModel.DataAnnotations;
utilizing Microsoft.Knowledge.Sqlite;
utilizing Dapper;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("TodoDb") ?? "Knowledge Supply=todos.db";
builder.Providers.AddScoped(_ => new SqliteConnection(connectionString));
builder.Providers.AddEndpointsApiExplorer();
builder.Providers.AddSwaggerGen();

var app = builder.Construct();

At this level we have got a SQLite connection string able to go scoped within the Providers Dependency Injection Container (fancy phrases for “it is within the pile of stuff we’ll be utilizing later”) and we have advised the system we wish a pleasant UI for our Open API (Swagger) net companies description. It is WSDL for JSON, children!

Then a name to EnsureDb which, ahem, ensures there is a database!

await EnsureDb(app.Providers, app.Logger);

What’s it appear to be? Just a bit make this desk if it does not exist motion:

async Activity EnsureDb(IServiceProvider companies, ILogger logger)
{
logger.LogInformation("Making certain database exists at connection string '{connectionString}'", connectionString);

utilizing var db = companies.CreateScope().ServiceProvider.GetRequiredService<SqliteConnection>();
var sql = $@"CREATE TABLE IF NOT EXISTS Todos (
{nameof(Todo.Id)} INTEGER PRIMARY KEY AUTOINCREMENT,
{nameof(Todo.Title)} TEXT NOT NULL,
{nameof(Todo.IsComplete)} INTEGER DEFAULT 0 NOT NULL CHECK({nameof(Todo.IsComplete)} IN (0, 1))
);";
await db.ExecuteAsync(sql);
}

Subsequent we’ll “map” some paths for /error in addition to paths for our API’s UI so once I hit /swagger with an online browser it seems good:

if (!app.Setting.IsDevelopment())
{
app.UseExceptionHandler("/error");
}

app.MapGet("/error", () => Outcomes.Drawback("An error occurred.", statusCode: 500))
.ExcludeFromDescription();

app.MapSwagger();
app.UseSwaggerUI();

Then sprinkle in slightly Hiya World simply to present of us a style:

app.MapGet("/", () => "Hiya World!")
.WithName("Hiya");

app.MapGet("/hey", () => new { Hiya = "World" })
.WithName("HelloObject");

You’ll be able to see how /hey would return a JSON object of Hiya: “World”

What’s that WithName bit on the finish? That names the API and corresponds to ‘operationId” within the generated swagger/openAPI json file. It is a shorthand for .WithMetadata(new EndpointNameMetadata("get_product")); which was absolutely no enjoyable in any respect.

Now let’s get some Todos from this database, lets? Here is all of them and simply the entire ones:

app.MapGet("/todos", async (SqliteConnection db) =>
await db.QueryAsync<Todo>("SELECT * FROM Todos"))
.WithName("GetAllTodos");

app.MapGet("/todos/full", async (SqliteConnection db) =>
await db.QueryAsync<Todo>("SELECT * FROM Todos WHERE IsComplete = true"))
.WithName("GetCompleteTodos");

Beautiful. However what’s this Todo object? We have not seen that. It is only a object that is formed proper. Maybe sooner or later that could possibly be a report fairly than a class however neither Dapper or EFCore assist that but it appears. Nonetheless, it is minimal.

public class Todo
{
public int Id { get; set; }
[Required]
public string? Title { get; set; }
public bool IsComplete { get; set; }
}

Let’s get slightly fancier with an API that will get a Todo nevertheless it won’t discover the consequence! It might produce an HTTP 200 OK or an HTTP 404 NotFound.

app.MapGet("/todos/{id}", async (int id, SqliteConnection db) =>
await db.QuerySingleOrDefaultAsync<Todo>("SELECT * FROM Todos WHERE Id = @id", new { id })
is Todo todo
? Outcomes.Okay(todo)
: Outcomes.NotFound())
.WithName("GetTodoById")
.Produces<Todo>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound);

Do not be unhappy in case you do not like SQL like this, it is only a selection amongst many. You need to use no matter ORM you need, fear not.

A thought: The .Produces are utilized by the OpenAPI/Swagger system. In my thoughts, it might be good to keep away from saying it twice because the Outcomes.Okay and Outcomes.NotFound is sitting proper there, however you’d want a Supply Generator or aspect-oriented submit compilation weaver to tack in on after the actual fact. That is the one half that I do not like.

Go discover the code and test it out for your self!


Try our Sponsor! YugabyteDB is a distributed SQL database designed for resilience and scale. It’s 100% open supply, PostgreSQL-compatible, enterprise-grade, and runs throughout all clouds. Enroll and get a free t-shirt!



About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, marketing consultant, father, diabetic, and Microsoft worker. He’s a failed stand-up comedian, a cornrower, and a e book writer.

facebook
twitter
subscribe
About   E-newsletter

Internet hosting By
Hosted in an Azure App Service










[ad_2]

Leave a Comment