Metadata
本部分详细介绍 Spring Data REST 所基于的应用程序提供的各种形式的元数据。
Application-Level Profile Semantics (ALPS)
ALPS is a data format for defining simple descriptions of application-level semantics, similar in complexity to HTML microformats. An ALPS document can be used as a profile to explain the application semantics of a document with an application-agnostic media type (such as HTML, HAL, Collection+JSON, Siren, etc.). This increases the reusability of profile documents across media types.
Spring Data REST 为每个导出的存储库提供一个 ALPS 文档。它包含有关 RESTful 转换和每个存储库属性的信息。
Spring Data REST 应用的根部是一个概要链接。假设你有一个同时包含 “人员” 和相关 “地址” 的应用,根文档将如下所示:
{
"_links" : {
"persons" : {
"href" : "http://localhost:8080/persons"
},
"addresses" : {
"href" : "http://localhost:8080/addresses"
},
"profile" : {
"href" : "http://localhost:8080/profile"
}
}
}
如 RFC 6906 中所定义的,概要文件链接是一个包含应用程序级别详细信息的地方。 ALPS draft spec 旨在定义一个特殊的概要文件格式,我们稍后将在本节中探讨它。
如果你导航到 “localhost:8080/profile” 处的概要链接,你看到的类似于以下内容的内容:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/profile"
},
"persons" : {
"href" : "http://localhost:8080/profile/persons"
},
"addresses" : {
"href" : "http://localhost:8080/profile/addresses"
}
}
}
在根级别,profile
是一个链接,并且不能提供超过一个应用程序配置文件。这就是为什么你必须导航到 /profile
以查找每个资源元数据的链接的原因。
如果你导航到 “/profile/persons” 并查看 “人员” 资源的概要数据,你看到的内容类似于以下示例:
{
"version" : "1.0",
"descriptors" : [ {
"id" : "person-representation", 1
"descriptors" : [ {
"name" : "firstName",
"type" : "SEMANTIC"
}, {
"name" : "lastName",
"type" : "SEMANTIC"
}, {
"name" : "id",
"type" : "SEMANTIC"
}, {
"name" : "address",
"type" : "SAFE",
"rt" : "http://localhost:8080/profile/addresses#address"
} ]
}, {
"id" : "create-persons", 2
"name" : "persons", 3
"type" : "UNSAFE", 4
"rt" : "#person-representation" 5
}, {
"id" : "get-persons",
"name" : "persons",
"type" : "SAFE",
"rt" : "#person-representation"
}, {
"id" : "delete-person",
"name" : "person",
"type" : "IDEMPOTENT",
"rt" : "#person-representation"
}, {
"id" : "patch-person",
"name" : "person",
"type" : "UNSAFE",
"rt" : "#person-representation"
}, {
"id" : "update-person",
"name" : "person",
"type" : "IDEMPOTENT",
"rt" : "#person-representation"
}, {
"id" : "get-person",
"name" : "person",
"type" : "SAFE",
"rt" : "#person-representation"
} ]
}
1 | 此 Person`资源的属性详细列表(标识为 `#person-representation )列出了属性名称。 |
2 | 支持的操作。此操作指示如何新建 Person 。 |
3 | name`是 `persons ,这表示(由于它是复数)应将 POST 应用于整个集合,而不是单个 person 。 |
4 | type`是 `UNSAFE ,因为此操作会改变系统的状态。 |
5 | rt`是 `#person-representation ,这表示返回的资源类型将是 `Person`资源。 |
此 JSON 文档的媒体类型为 |
你还可以从 “_links” 集合中找到一个 “profile” 链接,当你检查一个集合资源时,如下例所示:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/persons" 1
},
... other links ...
"profile" : {
"href" : "http://localhost:8080/profile/persons" 2
}
},
...
}
1 | 此 HAL 文档表示 `Person`集合。 |
2 | 它有一个 *profile*链接,指向同一 URI 以获取元数据。 |
同样地,profile
链接的默认作用是提供 ALPS。但是,如果您使用 Accept
header,则它可以提供 application/alps+json
。
Hypermedia Control Types
ALPS 为每个超媒体控件显示类型。它们包括:
Type | Description |
---|---|
SEMANTIC |
状态元素(例如 |
SAFE |
触发安全幂等状态转换的超媒体控件(例如 |
IDEMPOTENT |
触发不安全幂等状态转换的超媒体控件(例如 |
UNSAFE |
触发不安全非幂等状态转换的超媒体控件(例如 |
在前面显示的表述部分中,应用程序中的一些数据位被标记为 “SEMANTIC”。“address” 字段是一个涉及应安全的 “GET” 来检索的链接。因此,它被标记为 “SAFE”。超媒体操作本身映射到前表所示的类型。
ALPS with Projections
如果您定义任何投影,它们也列在 ALPS 元数据中。假设我们还定义了 inlineAddress
和 noAddresses
,它们将出现在相关的操作内。(请参见 “Projections” 以了解这两个投影的定义和讨论。)也就是说,GET 将出现在整个集合的操作中,而 GET 将出现在单个资源的操作中。以下示例显示了 get-persons
小节的备用版本:
...
{
"id" : "get-persons",
"name" : "persons",
"type" : "SAFE",
"rt" : "#person-representation",
"descriptors" : [ { 1
"name" : "projection",
"doc" : {
"value" : "The projection that shall be applied when rendering the response. Acceptable values available in nested descriptors.",
"format" : "TEXT"
},
"type" : "SEMANTIC",
"descriptors" : [ {
"name" : "inlineAddress", 2
"type" : "SEMANTIC",
"descriptors" : [ {
"name" : "address",
"type" : "SEMANTIC"
}, {
"name" : "firstName",
"type" : "SEMANTIC"
}, {
"name" : "lastName",
"type" : "SEMANTIC"
} ]
}, {
"name" : "noAddresses", 3
"type" : "SEMANTIC",
"descriptors" : [ {
"name" : "firstName",
"type" : "SEMANTIC"
}, {
"name" : "lastName",
"type" : "SEMANTIC"
} ]
} ]
} ]
}
...
1 | 出现了一个新属性 descriptors ,其中包含一个数组,即一个条目 projection 。 |
2 | 在 projection.descriptors`内部,我们可以看到 `inLineAddress 。它渲染 address 、firstName`和 `lastName 。在投影内部渲染的关系会导致包括内联数据字段。 |
3 | `noAddresses`提供了一个只包含 `firstName`和 `lastName`的子集。 |
借助所有这些信息,客户端不仅可以推断出可用的 RESTful 过渡,还可以在一定程度上推断出与后端交互所需的数据元素。
Adding Custom Details to Your ALPS Descriptions
您可以创建自定义消息,以显示在您的 ALPS 元数据中。为此,按如下所示创建 rest-messages.properties
:
rest.description.person=A collection of people
rest.description.person.id=primary key used internally to store a person (not for RESTful usage)
rest.description.person.firstName=Person's first name
rest.description.person.lastName=Person's last name
rest.description.person.address=Person's address
这些 rest.description.*
属性定义了显示在 Person
资源中的详细信息。它们会按如下所示更改 person-representation
的 ALPS 格式:
...
{
"id" : "person-representation",
"doc" : {
"value" : "A collection of people", 1
"format" : "TEXT"
},
"descriptors" : [ {
"name" : "firstName",
"doc" : {
"value" : "Person's first name", 2
"format" : "TEXT"
},
"type" : "SEMANTIC"
}, {
"name" : "lastName",
"doc" : {
"value" : "Person's last name", 3
"format" : "TEXT"
},
"type" : "SEMANTIC"
}, {
"name" : "id",
"doc" : {
"value" : "primary key used internally to store a person (not for RESTful usage)", 4
"format" : "TEXT"
},
"type" : "SEMANTIC"
}, {
"name" : "address",
"doc" : {
"value" : "Person's address", 5
"format" : "TEXT"
},
"type" : "SAFE",
"rt" : "http://localhost:8080/profile/addresses#address"
} ]
}
...
1 | `rest.description.person`的值映射到整个表示。 |
2 | `rest.description.person.firstName`的值映射到 `firstName`属性。 |
3 | `rest.description.person.lastName`的值映射到 `lastName`属性。 |
4 | `rest.description.person.id`的值映射到 `id`属性,这是一个通常不显示的字段。 |
5 | `rest.description.person.address`的值映射到 `address`属性。 |
提供这些属性设置将导致每个字段具有额外的 doc
属性。
Spring MVC(是 Spring Data REST 应用程序的核心内容)支持区域设置,这意味着您可以使用带有不同消息的多个属性文件进行捆绑。 |
JSON Schema
JSON Schema 是 Spring Data REST 支持的另一种元数据形式。根据其网站,JSON Schema 具有以下优点:
-
描述您现有的数据格式
-
清晰、人类和机器可读的文档
-
完成结构验证,适用于自动测试和验证客户端提交的数据
如 previous section 中所示,您可以通过从根 URI 导航到 profile
链接来获取此数据。
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/profile"
},
"persons" : {
"href" : "http://localhost:8080/profile/persons"
},
"addresses" : {
"href" : "http://localhost:8080/profile/addresses"
}
}
}
这些链接与前面显示的相同。要检索 JSON Schema,您可以使用以下 Accept
标头调用它们:application/schema+json
。
在这种情况下,如果您运行 curl -H 'Accept:application/schema+json' [role="bare"]http://localhost:8080/profile/persons
,您将看到类似于以下内容的输出:
{
"title" : "org.springframework.data.rest.webmvc.jpa.Person", 1
"properties" : { 2
"firstName" : {
"readOnly" : false,
"type" : "string"
},
"lastName" : {
"readOnly" : false,
"type" : "string"
},
"siblings" : {
"readOnly" : false,
"type" : "string",
"format" : "uri"
},
"created" : {
"readOnly" : false,
"type" : "string",
"format" : "date-time"
},
"father" : {
"readOnly" : false,
"type" : "string",
"format" : "uri"
},
"weight" : {
"readOnly" : false,
"type" : "integer"
},
"height" : {
"readOnly" : false,
"type" : "integer"
}
},
"descriptors" : { },
"type" : "object",
"$schema" : "https://json-schema.org/draft-04/schema#"
}
1 | 导出的类型 |
2 | A listing of properties |
如果资源有到其他资源的链接,则会有更多详细信息。
你还可以从 “_links” 集合中找到一个 “profile” 链接,当你检查一个集合资源时,如下例所示:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/persons" 1
},
... other links ...
"profile" : {
"href" : "http://localhost:8080/profile/persons" 2
}
},
...
}
1 | 此 HAL 文档表示 `Person`集合。 |
2 | 它有一个 *profile*链接,指向同一 URI 以获取元数据。 |
同样`profile` 链接默认提供 ALPS。如果您向它提供一个 application/schema+json
的 Accept
header,则它将呈现 JSON Schema 表示。