Minimal API Todo Sample

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Minimal API Todo Sample相关的知识,希望对你有一定的参考价值。

Minimal API Todo Sample

Intro

.NET 6 Preview 4 开始引入了 Minimal API 到如今的 RC1,Minimal API 也完善了许多并且修复了很多BUG,之前也写过文章介绍,可以参考:ASP.NET Core 6 Minimal API ,不过只是写了一个 Hello World, 最早还要 Using 现在默认启用了隐式命名空间可以不用在代码里写 using 了,今天就来用 Minimal API 来写一个简单的增删改查的 Todo API,一起来看下面的示例吧

Sample

下面的这个小示例,除了基本的增删改查 API 还包含了 swagger 的配置、 EF Core 的使用以及认证授权

示例代码如下:

var builder = WebApplication.CreateBuilder(args);

// 注册 DbContext
builder.Services.AddSqlite<TodoDbContext>(builder.Configuration.GetConnectionString("Todo"));
// 注册 swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new() { Title = "MinimalTodoAPI", Version = "v1" });
});
// 注册认证授权
builder.Services.AddAuthentication(QueryAuthenticationDefaults.AuthenticationSchema)
    .AddQuery();
builder.Services.AddAuthorization();

var app = builder.Build();
// 初始化数据库
using (var scope = app.Services.CreateScope())
{
    await scope.ServiceProvider.GetRequiredService<TodoDbContext>()
        .Database.EnsureCreatedAsync();
}
// 配置 HTTP 请求管道
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MinimalTodoAPI v1"));
}
app.Map("/health", Results.Ok);
app.MapGet("/contextSample", (HttpContext context) =>
 {
     return Results.Ok(context.Request.Query);
 }).ExcludeFromDescription(); // 从 swagger 中排除此 API

// Todo 的增删改查 API
app.MapGet("/api/todo", (TodoDbContext dbContext) => dbContext.TodoItems.AsNoTracking().ToArrayAsync());
app.MapPost("/api/todo", async (TodoItem item, TodoDbContext dbContext) => 
{
    if(string.IsNullOrWhiteSpace(item?.Title))
    {
        return Results.BadRequest();
    }
    item.Id = 0;
    item.CreatedAt = DateTime.UtcNow;
    dbContext.TodoItems.Add(item);
    await dbContext.SaveChangesAsync();
    return Results.Created($"/api/todo/{item.Id}", item);
});
app.MapPut("/api/todo/{id}", async (int id, TodoItem item, TodoDbContext dbContext) => 
{
    if(id <= 0 || string.IsNullOrWhiteSpace(item?.Title))
    {
        return Results.BadRequest();
    }
    var todo = await dbContext.TodoItems.FindAsync(id);
    if(todo is null)
    {
        return Results.NotFound();
    }
    todo.Title = item.Title;
    todo.Description = item.Description;
    todo.Done = item.Done;
    await dbContext.SaveChangesAsync();
    return Results.Ok(todo);
});

// 认证授权 
app.UseAuthentication();
app.UseAuthorization();

app.MapDelete("/api/todo/{id}", async (int id, TodoDbContext dbContext) =>
{
    if (id <= 0)
    {
        return Results.BadRequest();
    }
    var todo = await dbContext.TodoItems.FindAsync(id);
    if (todo is null)
    {
        return Results.NotFound();
    }
    dbContext.Remove(todo);
    await dbContext.SaveChangesAsync();
    return Results.Ok(todo);
}).RequireAuthorization();

app.Run();

上面示例注册 EF Core DbContext 的时候用的上次我们介绍的简化后的注册方式 EF Core 6 简化的数据库上下文注册

我们可以使用 MapGet/MapPost/MapPut/MapDelete 来限制请求方法,可以使用 Results 来方便的返回 API 结果, 类似于在 Controller 里调用 Ok/BadRequest/NotFound 等方法

swagger 界面:

swagger ui

我们来测试一下需要认证的 Delete API, 前面我们注册服务的时候使用了一个自定义的一个基于 query string 的认证方式以方便进行测试,下面我们来测试一下,首先需要调用 POST  API 来创建一个 todo,然后调用 GET API 来确认一下 todo 创建成功了,之后就可以测试我们的 DELETE API 了

我这里使用之前开发的 dotnet-httpie(dotnet-HTTPie) 来进行测试,你也可以使用 Postman 或者别的工具来测试

首先执行下面的命令

http delete -v --schema=https :7229/api/todo/1

HTTP 请求响应信息如下:

DELETE /api/todo/1 HTTP/1.1
Host: localhost:7229
Schema: https
User-Agent: dotnet-HTTPie/0.1.1

HTTP/1.1 401 Unauthorized
Content-Length: 0
Date: Sun, 19 Sep 2021 15:59:19 GMT
Server: Kestrel

这里我们没有提供任何的认证相关的信息,所以 API 返回了 401

接着我们提供认证信息来测试一下,在 query string 中添加 userId 和 userName 信息,执行下面的命令

http delete -v --schema=https :7229/api/todo/1 userId==1 userName==test

HTTP 请求响应信息如下:

DELETE /api/todo/1?userId=1&userName=test HTTP/1.1
Host: localhost:7229
Schema: https
User-Agent: dotnet-HTTPie/0.1.1

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Sun, 19 Sep 2021 16:04:29 GMT
Server: Kestrel
Transfer-Encoding: chunked

{"id":1,"title":"test","description":"test","done":false,"createdAt":"2021-09-19T15:57:31.3370653"}

可以看到此时返回了 200,已经删除成功了,不再是 401 了,我们也可以再调用一下 list API 来看一下是否真的被删除了,可以看到已经没有元素返回了

对于创建一个新 todo 的 POST API 也可以使用 dotnet-httpie 来方便的请求

More

对于简单的快速试错的 API 推荐使用 Minimal API 来实现,问题不大,但是比较复杂的应用个人还是推荐走 MVC/Web API 的形式,更为成熟,功能更全面,Minimal API 很多功能不支持或者支持的不太好,比如说 Minimal API 是不支持对 model 进行验证的,是没有 ModelState 的,即使 model 里声明了 Required 等验证,在 Minimal API 里也是不起作用的,也不支持 API-Version,另外对于 API 的分组支持也是比较弱的,要自己指定 tag 去分组,不如使用 Controller 简单方便

上面的源码可以在 Github 上获取 https://github.com/WeihanLi/SamplesInPractice/tree/master/net6sample/MinimalTodoAPI

对于 Minimal API 的使用,微软专门做了一个文档网站来介绍其使用,可以参考:https://minimal-apis.github.io/

另外微软的大佬 David 在 Gist 上也有一篇关于 Minimal API 的总结,可以参考:https://gist.github.com/davidfowl/ff1addd02d239d2d26f4648a06158727

References

以上是关于Minimal API Todo Sample的主要内容,如果未能解决你的问题,请参考以下文章

.Net Minimal API 介绍

创建API服务最小只要4行代码!!!尝新体验ASP.NET Core 6预览版本中的最小Web API(minimal APIS)新特性

简单聊下.NET6 Minimal API的使用方式

ASP.NET Core 6 Minimal API

详解 .Net6 Minimal API 的使用方式

.NET 6使用.NET 6开发minimal api以及依赖注入的实现VS2022热重载和自动反编译功能的演示