HATEOAS的RESTful服务。 超媒体:REST的秘密要素

在这篇文章中,我们将介绍有关HATEOAS的RESTful服务的综合文章。 超媒体是REST的秘密成分。

1.简介

在本教程的前一部分中,我们花了一些时间来刷新有关REST体系结构样式的基本原理的知识。 业界对REST状态的批判性眼光揭示了一个令人失望的事实,即它经常被完全忽略,它的关键约束之一,即作为应用程序状态引擎( HATEOAS )的超媒体

超媒体由嵌入在信息表示中或作为信息表示之上的应用程序控制信息的存在来定义。 分布式超媒体允许将表示和控制信息存储在远程位置。

https://www.ics.uci.edu/~fielding/pubs/dissertation/web_arch_domain.htm#sec_4_1_3

这部分的主题是超媒体 ,尤其是HATEOAS 。 希望我们不仅可以确信它的重要性,而且可以支持许多策略,以利用超媒体功能丰富我们的REST Web服务和API。

2.这些“噪音”是什么?

众所周知,无状态是REST体系结构风格的强制性约束之一。 另一方面,绝大多数现实世界的Web服务和API必须处理状态管理。 看起来REST忽略了现代软件系统的现实和需求吗?

绝对不是, REST体系结构风格承认状态管理的重要性,并以超媒体 (应用程序状态引擎)的形式提出了解决方案。 在服务器端, 超媒体的使用不仅通告资源之间的关系,而且通告可能潜在地应用于该资源的动作。 在客户端, 超媒体的存在带来了可发现性方面的下一步行动,步骤或要进行的状态转换。 理想情况下,客户端只需要知道一个URI入口点,其他所有内容都可以通过hypermedia来自服务器。

显然,客户端必须足够聪明,才能以可行的方式浏览超媒体控件。 正如许多经验丰富的Web服务和API开发人员已经注意到的那样,服务器上的超媒体支持并不是那么困难,而客户端则要困难得多。

但是,在Web服务和API的上下文中, 超媒体到底是什么? 我们可以将其视为服务器随响应发送给客户端的附加元信息。 它主要包括相关资源的链接,最重要的是,适用于所讨论资源以更改其状态的上下文操作。

当我说超文本时,我的意思是信息和控件的同时呈现,从而使信息成为用户通过其获得选择和选择动作的能力。 超媒体只是文本在媒体流中包含时间锚点的扩展。 大多数研究人员已经放弃了区分。

https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven#comment-718

总之,这些元数据片段告诉客户端在哪里获取更多数据或在当前上下文中哪种操作有效。 如果您觉得这很刺激,那确实是。

因此,我们讨论了什么是超媒体以及它在REST体系结构风格中的重要地位,现在该是我们讨论超媒体的“方式”的时候了。

3.野外的HATEOAS

仅重申我们在上一部分中所说的内容, REST体系结构样式要求使用超媒体 ,但未指定如何使用它。 显然,这个漏洞必须关闭,并且多年来导致了各种样式和规格的泛滥。 许多公司走得更远,提出了自己的超媒体类型,蓝图和建议。

超媒体类型是MIME媒体类型,其中包含导致应用程序流的本机超链接语义。 例如,HTML是一种超媒体类型。 XML不是。

http://amundsen.com/hypermedia/

令人惊讶的是,到目前为止,还没有一个普遍接受的标准可以遵循,以使用超媒体元素来授权Web服务和API。 一些或多或少被广泛采用,而另一些则占据相当狭窄的位置。 而且,大多数规范仍在发展之中,并且在进行中时被广告宣传。

为什么会有这么多规格,主要区别是什么? 总的来说,罪恶源于细节,更具体地说,是描述相关资源,链接和动作/操作。 如何找到最适合您的? 坦白地说,选择合适的规范会直接影响支持该规范所需的工作量。 如果是未开发的Web服务或API,您几乎可以自由选择。 相比之下,当您维护现有的Web服务或API并通过超媒体支持对其进行丰富的任务时,选择突然变得非常有限(除非您拥有完全重写的特权)。

从实现的角度来看,大多数规范都倾向于使用JSON格式来表示资源状态和超媒体控件。 但是,有些异常值会改用HTTP协议标头。 这当然不是REST架构风格所决定的,而是来自现代Web服务和API的现实,它们都是面向HTTP的。

因此,这些规格是什么?

RFC 5988(网络链接)

我们将从RFC-5988:Web链接开始 。 它为Web链接指定关系类型,为它们定义注册表,还定义HTTP头中带有特殊Link头的此类链接的使用。 这是一个简单的示例:

Link: <https://rentals.jcg.com/reservations>; rel="self"; title="reservations"

可以肯定的是, Link头(或多个Link头)中编码的Link可能不止一个,例如:

Link: <https://rentals.jcg.com/reservations?page=1>; rel="previous"; title="previous page", 
<https://rentals.jcg.com/reservations?page=3>; rel="next"; title="next page"

Web链接是引入超媒体支持的最基本,最简单的方法。 不管是使用新的还是现有的API,都可以很容易地将其接受,但是从功能角度来看, Web链接提供的选项集非常有限,主要是简单的关系,并且不支持动作和集合

哈尔

JSON超媒体API语言HAL建立使用JSON表示超媒体控件(链接和资源)的约定。 它由Mike Kelly于2011年创建。Web服务和API发出HAL文档,以便客户端可以提取适当的链接,并根据它们的关系类型在它们之间进行导航。

尽管HAL规范仍处于起草阶段 ,但其设计原理使其成为了由超媒体驱动的现代Web服务和API的最佳选择之一。

HAL的主要设计目标是通用性和简单性。 HAL可以应用于许多不同的域,并施加了满足超媒体API关键要求所需的最少结构量。

https://tools.ietf.org/id/draft-kelly-json-hal-02.html

您可能会猜到,资源表示形式是JSON格式的HAL文档 ,这些文档使用专用的媒体类型application/hal+json

{
  "_embedded": {
    "reservations": [ {
      "id": "ce5886acbb87",
      "vehicle": "Volkswagen Golf 1.2 TSI",
      "from": "2020-02-01",
      "to": "2020-02-12",
      "_links": {
        "self": {
          "href": "https://rentals.jcg.com/reservations/ce5886acbb87"
        },
        "customer": {
          "href": "https://rentals.jcg.com/customers/fed195a03e9d"
        }
      }
    }, {
      "id": "fc14e8ef90f5",
      "vehicle": "BMW 325i",
      "from": "2020-01-10",
      "to": "2020-01-12",
      "_links": {
        "self": {
          "href": "https://rentals.jcg.com/reservations/fc14e8ef90f5"
        },
        "customer": {
          "href": "https://rentals.jcg.com/customers/fed195a03e9d"
        }
      }
    } ]
  },
  "_links": {
    "first": {
      "href": "https://rentals.jcg.com/reservations?page=0&size=10"
    },
    "self": {
      "href": "https://rentals.jcg.com/reservations?page=0&size=10"
    },
    "next": {
      "href": "https://rentals.jcg.com/reservations?page=1&size=10"
    },
    "last": {
      "href": "https://rentals.jcg.com/reservations?page=1&size=10"
    }
  },
  "page": {
    "size": 10,
    "totalElements": 13,
    "totalPages": 2,
    "number": 0
  }
}

除此之外, HAL还支持URI模板和链接关系文档。 不幸的是, HAL不提供任何行动支持(您可能听说过的另一个名字是Provided )。 试图填补HAL空白的衍生规范之一是HAL-FORMS 。 从本质上讲,它只是HAL的扩展,通过表达方法和属性的能力来增强它。

{                                                                       
  "id": "13e1892765c5",                                                
  "vehicle": "Honda Civic 2020",                                       
  "from": "2020-01-01",                                                
  "to": "2020-01-05",                                                  
  "_links": {                                                          
    "customer": {                                                      
      "href": "https://rentals.jcg.com/customers/fed195a03e9d"           
    },                                                                  
    "self": {                                                          
      "href": "https://rentals.jcg.com/reservations/13e1892765c5"        
    }                                                                   
  },                                                                    
  "_templates": {                                                      
    "default": {                                                       
      "method": "put",                                                 
      "properties": [ {                                                
        "name": "from",
        "regex" : "yyyy-MM-dd",
        "required": true
      }, {                                                              
        "name": "to",
        "regex" : "yyyy-MM-dd",
        "required": true
      }, {                                                              
        "name": "vehicle"                                              
      } ]                                                               
    },                                                                  
    "delete": {                                                        
      "method": "delete",                                              
      "properties": [ ]                                                
    }                                                                   
  }                                                                     
}

请注意, HAL-FORMS旨在仅显示针对同一资源(或URI)可用的操作。 如果是JSON表示形式,则会为HAL-FORMS分配专用的媒体类型application/prs.hal-forms+json

JSON:API

JSON:API是受超媒体支持的Web服务和API的最广泛支持的标准之一。 它最初是由Yehuda Katz2013年起草的,此后越来越受欢迎。 您可能会猜到,它仅适用于JSON表示形式。

JSON:API旨在最大程度地减少请求数量和客户端与服务器之间传输的数据量。 在不影响可读性,灵活性或可发现性的情况下实现了这种效率。

https://jsonapi.org/format/

JSON:API规范描述了链接,资源关系和资源修改(相当于动作)的语义。 另外,它涵盖了表示错误的方式。

{                                                                                                             
  "data": {                                                                                                  
    "id": "13e1892765c5",                                                                                    
    "type": "reservation",                                                                                   
    "links": {                                                                                               
      "self": "https://rentals.jcg.com/reservations/13e1892765c5"
    },                                                                                                        
    "attributes": {                                                                                          
      "from": "2020-01-01",                                                                                  
      "to": "2020-01-05",                                                                                    
      "vehicle": "Honda Civic 2020"                                                                          
    },                                                                                                        
    "relationships": {                                                                                       
      "customer": {                                                                                          
        "links": {                                                                                           
          "self": "https://rentals.jcg.com/reservations/13e1892765c5/relationships/customer",              
          "related": "https://rentals.jcg.com/reservations/13e1892765c5/customer"                          
        }                                                                                                     
      }                                                                                                       
    }                                                                                                         
  }
}

使JSON:API脱颖而出的原因是,考虑了诸如排序,过滤,稀疏字段集和分页之类的获取(查询)模式,这些模式也是规范的一部分。

{
  "data": [
    {
      "id": "ce5886acbb87",
      "type": "reservation",
      "links": {
        "self": "https://rentals.jcg.com/reservations/ce5886acbb87"
      },
      "attributes": {
        "from": "2020-01-01",
        "to": "0120-01-12",
        "vehicle": "Volkswagen Golf 1.2 TSI"
      },
      "relationships": {
        "customer": {
          "links": {
            "self": "https://rentals.jcg.com/reservations/ce5886acbb87/relationships/customer",
            "related": "https://rentals.jcg.com/reservations/ce5886acbb87/customer"
          }
        }
      }
    },
    {
      "id": "fc14e8ef90f5",
      "type": "reservation",
      "links": {
        "self": "https://rentals.jcg.com/reservations/fc14e8ef90f5"
      },
      "attributes": {
        "from": "2020-01-10",
        "to": "2020-01-12",
        "vehicle": "BMW 325i"
      },
      "relationships": {
        "customer": {
          "links": {
            "self": "https://rentals.jcg.com/reservations/fc14e8ef90f5/relationships/customer",
            "related": "https://rentals.jcg.com/reservations/fc14e8ef90f5/customer"
          }
        }
      }
    }
  ],
  "links": {
    "first": "https://rentals.jcg.com/reservations?page[limit]=2",
    "last": "https://rentals.jcg.com/reservations?page[limit]=2&page[offset]=2",
    "next": "https://rentals.jcg.com/reservations?page[limit]=2&page[offset]=2"
  },
  "meta": {
    "totalResourceCount": 3
  }
}

公平地说, JSON:API具有非常简单,可读和可理解的格式。 为了实现这种折衷,它做出了一些明智的决定。 例如,您不会直接在JSON:API文档中看到操作。 实际上,它们根据HTTP协议是隐式和隐式的: POST用于创建, PATCH用于修改, DELETE用于删除。 这可能给客户带来一些解释上的困难,例如, PUT在哪里

尽管JSON:API规范的1.0版在2015年开始亮相,但它正在积极地研究之中,并被认为是一个不断发展的文档。 JSON:API已正确注册了媒体类型名称application/vnd.api+json并且还拥有自己的JSON模式 定义

JSON-LD

JSON-LD是链接数据的基于JSON的序列化,在2014年就获得了W3C候选正式建议的地位。它可能是最活跃的社区,而该规范的最新版本JSON-LD 1.1的字面意思是已发布。一个月前。 JSON-LD设计背后的关键原则强调能够轻松集成到已经使用JSON的现有系统中,并使用JSON-LD语义对其进行扩充,而不会破坏已建立的联系。

可以肯定地说, JSON-LD与链接数据有关的不是超媒体,而是其表达信息,上下文和关系的丰富功能非常适合某些超媒体承诺。

{                                                               
  "@context": {                                                
    "@vocab": "http://schema.org/"                             
  },                                                            
  "@type": "Reservation",                                      
  "id": "13e1892765c5",                             
  "vehicle": "Honda Civic 2020",                               
  "from": "2020-01-01",                      
  "to": "2020-01-05",                        
  "customer": {                                                
    "@id": "https://rentals.jcg.com/customers/fed195a03e9d"      
  },                                                            
  "@id": "https://rentals.jcg.com/reservations/13e1892765c5"     
}

JSON-LD的缺点之一是它缺乏对动作的支持。 Hydra解决了JSON-LD的主要缺点, Hydra超媒体驱动的Web服务和API的词汇。

Hydra的基本思想是提供一个词汇表,该词汇表可使服务器将有效的状态转换通告给客户端。 然后,客户端可以使用此信息来构造HTTP请求,该请求将修改服务器的状态,从而实现某个所需的目标。

http://www.hydra-cg.com/spec/latest/core/#hydra-at-a-glance

为了了解它是如何工作的,让我们看一下使用Hydra语义丰富的JSON-LD文档的快速示例。

{
  "@context": {
    "@vocab": "http://schema.org/",
    "hydra": "http://www.w3.org/ns/hydra/core#"
  },
  "@type": "hydra:Collection",
  "hydra:collection": [ {
    "@type": "hydra:Collection",
    "@id": "https://rentals.jcg.com/reservations",
    "hydra:manages": {
      "hydra:property": "self",
      "hydra:subject": "https://rentals.jcg.com/reservations"
    },
    "hydra:operation": [ {
      "hydra:method": "GET"
    } ]
  } ],
  "hydra:member": [ {
    "@type": "Reservation",
    "vehicle": "Volkswagen Golf 1.2 TSI",
    "from": "2020-02-01",
    "to": "2020-02-12",
    "customer": {
      "@id": "https://rentals.jcg.com/customers/fed195a03e9d",
      "hydra:operation": [ {
        "hydra:method": "GET"
      } ]
    },
    "@id": "https://rentals.jcg.com/reservations/ce5886acbb87",
    "hydra:operation": [ {
      "hydra:method": "GET"
    }, {
      "hydra:method": "PUT",
      "hydra:expects": {
        "@type": "UpdateReservation",
        "hydra:supportedProperty": [ {
          "hydra:property": "from"
        }, {
          "hydra:property": "to"
        }, {
          "hydra:property": "vehicle"
        } ]
      }
    }, {
      "hydra:method": "DELETE"
    } ],
    "id": "ce5886acbb87"
  }, {
    "@type": "Reservation",
    "vehicle": "BMW 325i",
    "from": "2020-01-10",
    "to": "2020-01-12",
    "customer": {
      "@id": "https://rentals.jcg.com/customers/fed195a03e9d",
      "hydra:operation": [ {
        "hydra:method": "GET"
      } ]
    },
    "@id": "https://rentals.jcg.com/reservations/fc14e8ef90f5",
    "hydra:operation": [ {
      "hydra:method": "GET"
    }, {
      "hydra:method": "PUT",
      "hydra:expects": {
        "@type": "UpdateReservation",
        "hydra:supportedProperty": [ {
          "hydra:property": "from"
        }, {
          "hydra:property": "to"
        }, {
          "hydra:property": "vehicle"
        } ]
      }
    }, {
      "hydra:method": "DELETE"
    } ],
    "id": "fc14e8ef90f5"
  } ],
  "hydra:totalItems": 3,
  "hydra:view": {
    "@type": "hydra:PartialCollectionView",
    "hydra:next": "https://rentals.jcg.com/reservations?page=1&size=2",
    "hydra:first": "https://rentals.jcg.com/reservations?page=0&size=2",
    "hydra:last": "https://rentals.jcg.com/reservations?page=1&size=2"
  }
}

再重申一次, JSON-LD的最强之处是数据链接。 与Hydra结合使用,您的Web服务和API将获得成熟的超媒体功能,但是集成可能并不像人们期望的那么容易。 JSON-LD具有保留的媒体application/ld+json

警笛

SirenKevin Swiber于2012年撰写,是用于表示实体的超媒体规范。 Siren词汇表中的实体是URI可寻址资源,具有与之关联的属性,操作和可导航链接。 值得注意的是, Siren是专门为Web服务和API设计的,例如,动作可以直接映射到HTTP协议动词。

{                                                                                                    
  "class": [ "reservation" ],                                                                       
  "properties": {                                                                                   
    "id": "13e1892765c5",                                                                
    "from": "2020-01-01",
    "to": "2020-01-05", 
    "vehicle": "Honda Civic 2020"                                                                   
  },                                                                                                 
  "entities": [ {                                                                                   
    "rel": [ "customer" ],                                                                          
    "href": "https://rentals.jcg.com/customers/fed195a03e9d"                                          
  }, {                                                                                               
    "class": [ "customer" ],                                                                        
    "rel": [ "http://schema.org/customer" ],                                                        
    "properties": {                                                                                 
      "firstName": "John",                                                                          
      "lastName": "Smith",                                                                          
      "id" : "fed195a03e9d"                                                                  
    }                                                                                                
  } ],                                                                                               
  "actions": [ {                                                                                    
    "name": "update",                                                                               
    "method": "PUT",                                                                                
    "href": "https://rentals.jcg.com/reservations/13e1892765c5",                                      
    "fields": [ {                                                                                   
      "name": "from",                                                                               
      "type": "date"                                                                                
    }, {                                                                                             
      "name": "to",                                                                                 
      "type": "date"                                                                                
    }, {                                                                                             
      "name": "vehicle",                                                                            
      "type": "text"                                                                                
    } ]                                                                                              
  }, {                                                                                               
    "name": "delete",                                                                               
    "method": "DELETE",                                                                             
    "href": "https://rentals.jcg.com/reservations/13e1892765c5"                                       
  } ],                                                                                               
  "links": [ {                                                                                      
    "rel": [ "self" ],                                                                              
    "href": "https://rentals.jcg.com/reservations/13e1892765c5"                                       
  } ]                                                                                                
}

尽管年代久远, Siren仍被列为进行中的作品。 它本身不像HALJSON:API那样流行,但是它相对简单和Web API优先语义使其成为值得考虑的选项。 Siren JSON表示形式的媒体类型为application/vnd.siren+json

集合+ JSON

Mike Amundsen在2011年创建的Collection + JSON规范旨在成为一种超媒体类型,旨在支持读取,编写和查询简单集合。 它在某种程度上受到Atom联合格式(RFC-4287)Atom发布协议(RFC-5023)的启发。 关于Collection + JSON的一个有趣事实是,它将所有内容都视为一个集合,因此,单个项目表示为一个元素的集合。

{
  "collection": {
    "version": "1.0",
    "href": "https://rentals.jcg.com/reservations/13e1892765c5",
    "links": [ {
      "rel": "customer",
      "href": "https://rentals.jcg.com/customers/fed195a03e9d"
    } ],
    "items": [ {
      "href": "https://rentals.jcg.com/reservations/13e1892765c5",
      "data": [ {
        "name": "from",
        "value": "2020-01-01"
      }, {
        "name": "id",
        "value": "13e1892765c5"
      }, {
        "name": "to",
        "value": "2020-01-05"
      }, {
        "name": "vehicle",
        "value": "Honda Civic 2020"
      } ],
      "links": [ {
        "rel": "customer",
        "href": "https://rentals.jcg.com/customers/fed195a03e9d"
      } ]
    } ],
    "template": {
      "data": [ {
        "name": "from",
        "value": ""
      }, {
        "name": "to",
        "value": ""
      }, {
        "name": "vehicle",
        "value": ""
      } ]
    }
  }
}

您可能会猜到, Collection + JSON标准非常适合列表和集合。 它还包括对查询模板 (链接和关系)和写模板 (操作)的支持,以及标准化的错误报告。

在某些时候, Collection + JSON非常流行,但是与其他替代方案相比,它实现起来可能更困难。 同样,对“万物都是收藏”的偏见是不直观的。

Collection + JSON的媒体类型为application/vnd.collection+json

优步

UBER 超媒体类型描述了对简单状态转移和临时转移的支持。 它是由Mike Amundsen (是Collection + JSON的作者)和Irakli Nadareishvili于2014年左右共同创建的,同时针对XML和JSON变体。

那么,作者提出另一种超媒体类型的动机是什么? 迈克·阿蒙森Mike Amundsen)的这则推文使推理过程更加清晰。

Collection + JSON是高度结构化的CRUD格式。 HAL适用于内联超媒体, Siren具有丰富的obj模型。 UBER开放且极简。

https://twitter.com/mamund/status/456508872832716800

UBER文档支持链接关系,操作和错误报告机制。 该规范旨在与多种协议一起使用,但包括有关基于HTTP的实现和解释的详细指南。

{
  "uber": {
    "version": "1.0",
    "data": [ {
      "name": "customer",
      "rel": [ "customer" ],
      "url": "https://rentals.jcg.com/customers/fed195a03e9d"
    }, {
      "name": "self",
      "rel": [ "self" ],
      "url": "https://rentals.jcg.com/reservations/13e1892765c5"
    }, {
      "name": "update",
      "rel": [ "update" ],
      "url": "https://rentals.jcg.com/reservations/13e1892765c5",
      "action": "replace",
      "model": "from={from}&to={to}&vehicle={vehicle}"
    }, {
      "name": "delete",
      "rel": [ "delete" ],
      "url": "https://rentals.jcg.com/reservations/13e1892765c5",
      "action": "remove",
      "model": ""
    }, {
      "name": "reservation",
      "data": [ {
        "name": "from",
        "value": "2020-01-01"
      }, {
        "name": "id",
        "value": "13e1892765c5"
      }, {
        "name": "to",
        "value": "2020-01-05"
      }, {
        "name": "vehicle",
        "value": "Honda Civic 2020"
      } ]
    } ]
  }
}

自2016年以来,它仍被标记为草稿(准确地说是稳定的草稿),并且没有太大变化。它没有正式注册的媒体类型,因此,如果使用JSON表示,则必须使用application/vnd.amundsen-uber+json

亚哈皮

有许多鲜为人知的超媒体规范值得关注。 我们将从 2014年首次发布的Another Hypermedia(ish)API规范( Yahapi )开始,该规范本质上是启用 超媒体的约定的列表。

最后, Yahapi只是使您的API看起来漂亮,简单且一致的首选项列表。

https://github.com/Yahapi/yahapi

Yahapi提供了分页,排序,部分结果和错误格式的准则列表,支持链接和关系,但不幸的是不支持操作。 它很少在野外发现并且不是真正活跃。 Yahapi文档的媒体类型仅为application/json

石匠

Mason是一种基于JSON的格式,用于将超媒体元素引入经典的JSON数据表示中。 特别是,它包括用于链接和动作的超媒体元素以及标准化的错误处理。 Mason在媒体类型注册表中注册为application/vnd.mason+json

离子

Ion将自身定位为REST的一种基于JSON的直观超媒体类型。 它涵盖了关系类型的链接以及使用表单的操作 。 不幸的是,自2018年以来,该规范似乎处于休眠状态。分配给Ion内容的媒体类型为application/ion+json

4. HATEOAS的成本

此时,您应该对将超媒体HATEOAS应用于RESTful Web服务和API时的作用有一个很好的了解。 而且,如果您是从事典型企业项目的经验丰富的软件开发人员,您可能很难记得上一次遇到HATEOAS时的情况。 让我们面对现实:没有人知道如何使用超媒体

REST体系结构的上下文中, HATEOAS是必须的,但它不是免费的,并且会产生成本,有时非常重要。 不仅在实施方面,而且在前期设计方面。 在这方面,服务器相对容易,但是客户端确实很困难(充其量您可能会获得Link标头的支持)。 实际上,这意味着即使您开发完美的RESTful Web服务或API,其他开发人员也有很大可能选择完全不在其客户端中使用超媒体。

在本教程的这一部分中,我们讨论了许多不同的超媒体规范。 除少数例外,其中大多数带有“进行中”或“不稳定”的标签。 总的来说,这意味着仍有黑暗的水域在航行,而您最终到达那里的机会很高。 这就是为什么要持续不断地创建新规范的原因之一。 显然,每个规范需要非常不同的设计和实现工作量。 希望您的编程语言或平台生态系统已经有了一些库和框架来帮助您入门,但总的来说并非如此。

在服务器和客户端之间的数据交换方面, 超媒体可能会导致更多往返,以获取链接和关系背后的其他详细信息。 由于需要包括链接和操作,这也可能导致资源表示的大小显着增加。

您可能会问自己一个有趣的问题,即REST架构风格(尤其是HATEOAS)如何与微服务架构融合? 为了说明问题,请考虑一个只有两个 Customer Service的系统,即Customer ServiceReservation Service 。 由于客户不需要任何额外的知识或前期知识,他们如何发现有多种服务? Reservation Service如何整合与客户相关的超媒体元素,反之亦然? 很有可能由另一层(如API网关或/和聚合器)负责 ,当然这听起来并不简单。

如果此时您不惧怕超媒体HATEOAS ,请不要担心。 收益大大超过了所需的成本和精力,尤其是从长期来看。 作为对此的确认,让我们看一下简短而简单的案例研究。

5.案例研究

我们将要分析的示例应用程序是一个汽车租赁平台,该平台目前仅实现两个RESTful Web API来管理reservationscustomers 。 与任何客户端共享的唯一知识是平台的入口点,出于演示目的,假设在伪造的URL https://rentals.jcg.com后面有服务器。

该端点仅接受HTTP GET请求并返回超媒体文档(使用HALHAL-FORMS ),示例如下所示。

$ curl https://rentals.jcg.com/
{                                                        
  "_links": {                                           
    "self": {                                           
      "href": "https://rentals.jcg.com/"                  
    },                                                   
    "reservations": {                                   
      "href": "https://rentals.jcg.com/reservations"      
    },                                                   
    "customers" : {                                      
      "href": "https://rentals.jcg.com/customers"         
    }                                                    
  }                                                      
}

一旦了解超媒体的客户收到此类文档,便可以清楚地了解到可以从那里导航到两个链接: reservationscustomers 。 在这种情况下,客户对reservations感兴趣,因此就去了那里。

$ curl -iv https://rentals.jcg.com/reservations
{
  "_embedded": {
    "reservations": [ {
      "id": "ce5886acbb87",
      "vehicle": "Volkswagen Golf 1.2 TSI",
      "from": "2020-02-01",
      "to": "2020-02-12",
      "_links": {
        "customer": {
          "href": "https://rentals.jcg.com/customers/fed195a03e9d"
        },
        "self": {
          "href": "https://rentals.jcg.com/reservations/ce5886acbb87"
        }
      },
      "_templates": {
        "default": {
          "method": "put",
          "properties": [ {
            "name": "from",
            "regex" : "yyyy-MM-dd",
            "required": true
          }, {
            "name": "to",
            "regex" : "yyyy-MM-dd",
            "required": true
          }, {
            "name": "vehicle",
            "required": true
          } ]
        },
        "delete": {
          "method": "delete",
          "properties": [ ]
        }
      }
    }, 
    ...
    ]
  },
  "_links": {
    "self": {
      "href": "https://rentals.jcg.com/reservations"
    }
  },
  "_templates": {
    "default": {
      "method": "post",
      "properties": [ {
        "name": "from",
        "regex" : "yyyy-MM-dd",
        "required": true
      }, {
        "name": "to",
        "regex" : "yyyy-MM-dd",
        "required": true
      }, {
        "name": "vehicle",
        "required": true
      } ]
    }
  }
}

这次服务器返回强大的资源表示形式(为简单起见,集合中仅保留一个保留项),其中包含许多超媒体元素,因此客户端有多种选择。

例如,通过检查_templates 超媒体元素,它发现它可以通过在有效负载中提交带有fromtovehicle属性的HTTP POST请求来创建新的保留(因为它是HAL-FORMS ,所以使用application/x-www-form-urlencoded表单编码)。 您可能会注意到,尽管存在一些约束,但没有任何迹象表明fromtovehicle属性的类型(字符串?日期?数字?)是什么。

"_templates": {
  "default": {
    "method": "post",
    "properties": [ {
      "name": "from",
      "regex" : "yyyy-MM-dd",
      "required": true
    }, {
      "name": "to",
      "regex" : "yyyy-MM-dd",
      "required": true
    }, {
      "name": "vehicle",
      "required": true
    } ]
  }
}

备选地,客户端可以通过自省相关联的_templates 超媒体元素来表达对特定保留的兴趣。

"_templates": {
  "default": {
    "method": "put",
    "properties": [ {
      "name": "from",
      "regex" : "yyyy-MM-dd",
      "required": true
    }, {
      "name": "to",
      "regex" : "yyyy-MM-dd",
      "required": true
    }, {
      "name": "vehicle",
      "required": true
    } ]
  },
  "delete": {
    "method": "delete",
    "properties": [ ]
  }
}

在这种情况下,服务器提供使用HTTP PUT请求(完全替换语义)更新保留或使用HTTP DELETE请求完全删除特定保留的选择。

超媒体–结论

在本教程的这一部分中,我们讨论了超媒体HATEOAS ,这是任何RESTful Web服务或API的组成部分。 超媒体规范的前景并非一成不变,并且在不断变化。 我们进行了很多选择,但没有遇到明显的赢家。 这样做的原因是,每一个都有不同的权衡,您需要确定哪种超媒体规范最适合您的应用程序需求。 上下文很重要,因此请认真对待。 您可能会发现有关为API选择超媒体类型的文章-HAL,JSON-LD,Collection + JSON,SIREN,噢,我的天哪!Kevin Sookocheff提供的帮助很大。

7.接下来

在本教程的下一部分中,我们将讨论文档在由hypermedia支持的RESTful Web服务和API的生命周期中的作用。

翻译自: https://www.javacodegeeks.com/restful-services-with-hateoas-hypermedia-the-secret-ingredient-of-rest.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值