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 界面:
我们来测试一下需要认证的 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.1HTTP/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.1HTTP/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
https://github.com/WeihanLi/SamplesInPractice/tree/master/net6sample/MinimalTodoAPI
https://github.com/Minimal-APIs/minimal-apis.github.io
https://minimal-apis.github.io/
https://gist.github.com/davidfowl/ff1addd02d239d2d26f4648a06158727
ASP.NET Core 6 Minimal API
使用 Minimal API 改造动态文件提供者