"postdate" : "2015-05-30T21:41:12.650Z"

时间:2022-06-10 03:06:29

  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: