Hypermedia As The Engine Of Application State (HATEOAS)
HATEOAS(Hypermedia as the engine of application state)是 REST 架构气势派头中最庞大的约束,也是构建成熟 REST 处事的核心。它的重要性在于冲破了客户端和处事器之间严格的契约,,使得客户端可以越发智能和自适应,而 REST 处事自己的演化和更新也变得越发容易。
HATEOAS的长处有:
具有可进化性并且能自我描述
超媒体(Hypermedia, 例如超链接)驱动如何消费和使用API, 它报告客户端如何使用API, 如何与API交互, 例如: 如何删除资源, 更新资源, 创建资源, 如何访谒下一页资源等等.
例如下面就是一个不使用HATEOAS的响应例子:
{ "id" : 1, "body" : "My first blog post", "postdate" : "2015-05-30T21:41:12.650Z" ?}
如果不使用HATEOAS的话, 可能会有这些问题:
客户端更多的需要了解API内在逻辑
如果API产生了一点变革(添加了特别的法则, 转变法则)城市粉碎API的消费者.
API无法独立于消费它的应用进行进化.
如果使用HATEOAS:
{
"id" : 1,
"body" : "My first blog post",
"postdate" : "2015-05-30T21:41:12.650Z",
"links" : [
{
"rel" : "self",
"href" : http://blog.example.com/posts/{id},
"method" : "GET"
},
{
"rel": "update-blog",
"href": {id},
"method" "PUT"
}
....
]
}
这个response里面包罗了若干link, 第一个link包罗着获取当前响应的链接, 第二个link则报告客户端如何去更新该post.
Roy Fielding的一句名言: "如果在部署的时候客户端把它们的控件都嵌入到了设计中, 那么它们就无法获得可进化性, 控件必需可以实时的被发明. 这就是超媒体能做到的." ????
好比说针对上面的例子, 我可以在不转变响应主体功效的情况下添加此外一个删除的成果(link), 客户端通过响应里的links就会发明这个删除成果, 但是对其他部分都没有影响.
所以说HTTP协议还是很撑持HATEOAS的:
如果你仔细想一下, 这就是我们平时浏览网页的方法. 浏览网站的时候, 我们并不关心网页里面的超链接地点是否变革了, 只要知道超链接是干什么就可以.
我们可以点击超链接进行跳转, 也可以提交表单, 这就是超媒体驱动应用措施(浏览器)状态的例子.
如果处事器决定转变超链接的地点, 客户端措施(浏览器)并不会因为这个转变而产生故障, 这就浏览器使用超媒体响应来报告我们下一步该怎么做.
那么怎么展示这些link呢?
JSON和XML并没有如何展示link的观点. 但是HTML却知道, anchor元素:
<a href="http://www.mamicode.com/uri" type="media type">
href包罗了URI
rel则描述了link如何和资源的关系
type是可选的, 它暗示了媒体的类型
为了撑持HATEOAS, 这些形式就很有用了:
{ ... "links" : [ { "rel" : "self", "href" : http://blog.example.com/posts/{id}, "method" : "GET" } .... ] }
method: 界说了需要使用的要领
rel: 表白了行动的类型
href: 包罗了执行这个行动所包罗的URI.
为了让ASP.NET Core Web API 撑持HATEOAS, 得需要本身手动编写代码实现. 有两种步伐:
静态类型方案: 需要基类(包罗link)和包装类, 也就是返回的资源的ViewModel里面都含有link, 通过担任于同一个基类来实现.
动态类型方案: 需要使用例如匿名类或ExpandoObject等, 对付单个资源可以使用ExpandoObject, 而对付调集类资源则使用匿名类.
这一篇文章介绍如何实施第一种方案 -- 静态类型方案首先需要筹备一个asp.net core 2.0 web api的项目. 项目搭建的过程就不介绍了, 我的很多文章里都有介绍.
下面开始成立Domain Model -- Vehicle.cs:
using SalesApi.Core.Abstractions.DomainModels; namespace SalesApi.Core.DomainModels { public class Vehicle: EntityBase { public string Model { get; set; } public string Owner { get; set; } } }
这里的父类EntityBase是我的项目特有的, 您可能不需要.
然后为这个类添加约束(数据库映射的字段长度, 必填等等) VehicleConfiguration.cs:
using Microsoft.EntityFrameworkCore.Metadata.Builders; using SalesApi.Core.Abstractions.DomainModels; namespace SalesApi.Core.DomainModels { public class VehicleConfiguration : EntityBaseConfiguration<Vehicle> { public override void ConfigureDerived(EntityTypeBuilder<Vehicle> b) { b.Property(x => x.Model).IsRequired().HasMaxLength(50); b.Property(x => x.Owner).IsRequired().HasMaxLength(50); } } }
然后把Vehicle添加到SalesContext.cs: