Metadata

本部分详细介绍 Spring Data REST 所基于的应用程序提供的各种形式的元数据。

This section details the various forms of metadata provided by a Spring Data REST-based application.

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 provides an ALPS document for every exported repository. It contains information about both the RESTful transitions and the attributes of each repository.

Spring Data REST 应用的根部是一个概要链接。假设你有一个同时包含 “人员” 和相关 “地址” 的应用,根文档将如下所示:

At the root of a Spring Data REST app is a profile link. Assuming you had an app with both persons and related addresses, the root document would be as follows:

{
  "_links" : {
    "persons" : {
      "href" : "http://localhost:8080/persons"
    },
    "addresses" : {
      "href" : "http://localhost:8080/addresses"
    },
    "profile" : {
      "href" : "http://localhost:8080/profile"
    }
  }
}

RFC 6906 中所定义的,概要文件链接是一个包含应用程序级别详细信息的地方。 ALPS draft spec 旨在定义一个特殊的概要文件格式,我们稍后将在本节中探讨它。

A profile link, as defined in RFC 6906, is a place to include application-level details. The ALPS draft spec is meant to define a particular profile format, which we explore later in this section.

如果你导航到 “localhost:8080/profile” 处的概要链接,你看到的类似于以下内容的内容:

If you navigate into the profile link at localhost:8080/profile, you see content resembling the following:

{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/profile"
    },
    "persons" : {
      "href" : "http://localhost:8080/profile/persons"
    },
    "addresses" : {
      "href" : "http://localhost:8080/profile/addresses"
    }
  }
}

在根级别,profile 是一个链接,并且不能提供超过一个应用程序配置文件。这就是为什么你必须导航到 /profile 以查找每个资源元数据的链接的原因。

At the root level, profile is a single link and cannot serve up more than one application profile. That is why you must navigate to /profile to find a link for each resource’s metadata.

如果你导航到 “/profile/persons” 并查看 “人员” 资源的概要数据,你看到的内容类似于以下示例:

If you navigate to /profile/persons and look at the profile data for a Person resource, you see content resembling the following example:

{
  "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 A detailed listing of the attributes of a Person resource, identified as #person-representation, lists the names of the attributes.
2 The supported operations. This one indicates how to create a new Person.
3 The name is persons, which indicates (because it is plural) that a POST should be applied to the whole collection, not a single person.
4 The type is UNSAFE, because this operation can alter the state of the system.
5 The rt is #person-representation, which indicates that returned resource type will be Person resource.

此 JSON 文档的媒体类型为 application/alps+json。这与前一个 JSON 文档不同,前一个 JSON 的媒体类型为 application/hal+json。这些格式不同,受不同的规范管理。

This JSON document has a media type of application/alps+json. This is different from the previous JSON document, which had a media type of application/hal+json. These formats are different and governed by different specs.

你还可以从 “_links” 集合中找到一个 “profile” 链接,当你检查一个集合资源时,如下例所示:

You can also find a profile link in the collection of _links when you examine a collection resource, as the following example shows:

{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/persons" 1
    },
    ... other links ...
    "profile" : {
      "href" : "http://localhost:8080/profile/persons" 2
    }
  },
  ...
}
1 This HAL document respresents the Person collection.
2 It has a profile link to the same URI for metadata.

同样地,profile 链接的默认作用是提供 ALPS。但是,如果您使用 Accept header,则它可以提供 application/alps+json

Again, by default, the profile link serves up ALPS. However, if you use an Accept header, it can serve application/alps+json.

Hypermedia Control Types

ALPS 为每个超媒体控件显示类型。它们包括:

ALPS displays types for each hypermedia control. They include:

Table 1. ALPS types
Type Description

SEMANTIC

A state element (such as HTML.SPAN, HTML.INPUT, and others).

SAFE

A hypermedia control that triggers a safe, idempotent state transition (such as GET or HEAD).

IDEMPOTENT

A hypermedia control that triggers an unsafe, idempotent state transition (such as PUT or DELETE).

UNSAFE

A hypermedia control that triggers an unsafe, non-idempotent state transition (such as POST).

在前面显示的表述部分中,应用程序中的一些数据位被标记为 “SEMANTIC”。“address” 字段是一个涉及应安全的 “GET” 来检索的链接。因此,它被标记为 “SAFE”。超媒体操作本身映射到前表所示的类型。

In the representation section shown earlier, bits of data from the application are marked as being SEMANTIC. The address field is a link that involves a safe GET to retrieve. Consequently, it is marked as being SAFE. Hypermedia operations themselves map onto the types as shown in the preceding table.

ALPS with Projections

如果您定义任何投影,它们也列在 ALPS 元数据中。假设我们还定义了 inlineAddressnoAddresses,它们将出现在相关的操作内。(请参见 “Projections” 以了解这两个投影的定义和讨论。)也就是说,GET 将出现在整个集合的操作中,而 GET 将出现在单个资源的操作中。以下示例显示了 get-persons 小节的备用版本:

If you define any projections, they are also listed in the ALPS metadata. Assuming we also defined inlineAddress and noAddresses, they would appear inside the relevant operations. (See “Projections” for the definitions and discussion of these two projections.) That is GET would appear in the operations for the whole collection, and GET would appear in the operations for a single resource. The following example shows the alternate version of the get-persons subsection:

...
  {
    "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 A new attribute, descriptors, appears, containing an array with one entry, projection.
2 Inside the projection.descriptors, we can see inLineAddress. It render address, firstName, and lastName. Relationships rendered inside a projection result in including the data fields inline.
3 noAddresses serves up a subset that contains firstName and lastName.

借助所有这些信息,客户端不仅可以推断出可用的 RESTful 过渡,还可以在一定程度上推断出与后端交互所需的数据元素。

With all this information, a client can deduce not only the available RESTful transitions but also, to some degree, the data elements needed to interact with the back end.

Adding Custom Details to Your ALPS Descriptions

您可以创建自定义消息,以显示在您的 ALPS 元数据中。为此,按如下所示创建 rest-messages.properties

You can create custom messages that appear in your ALPS metadata. To do so, create rest-messages.properties, as follows:

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 格式:

These rest.description.* properties define details to display for a Person resource. They alter the ALPS format of the person-representation, as follows:

...
  {
    "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 The value of rest.description.person maps into the whole representation.
2 The value of rest.description.person.firstName maps to the firstName attribute.
3 The value of rest.description.person.lastName maps to the lastName attribute.
4 The value of rest.description.person.id maps to the id attribute, a field not normally displayed.
5 The value of rest.description.person.address maps to the address attribute.

提供这些属性设置将导致每个字段具有额外的 doc 属性。

Supplying these property settings causes each field to have an extra doc attribute.

Spring MVC(是 Spring Data REST 应用程序的核心内容)支持区域设置,这意味着您可以使用带有不同消息的多个属性文件进行捆绑。

Spring MVC (which is the essence of a Spring Data REST application) supports locales, meaning you can bundle up multiple properties files with different messages.

JSON Schema

JSON Schema 是 Spring Data REST 支持的另一种元数据形式。根据其网站,JSON Schema 具有以下优点:

JSON Schema is another form of metadata supported by Spring Data REST. Per their website, JSON Schema has the following advantages:

  • Describes your existing data format

  • Clear, human- and machine-readable documentation

  • Complete structural validation, useful for automated testing and validating client-submitted data

previous section 中所示,您可以通过从根 URI 导航到 profile 链接来获取此数据。

As shown in the previous section, you can reach this data by navigating from the root URI to the profile link.

{
  "_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

These links are the same as shown earlier. To retrieve JSON Schema, you can invoke them with the following Accept header: application/schema+json.

在这种情况下,如果您运行 curl -H 'Accept:application/schema+json' [role="bare"]http://localhost:8080/profile/persons,您将看到类似于以下内容的输出:

In this case, if you ran curl -H 'Accept:application/schema+json' [role="bare"]http://localhost:8080/profile/persons, you would see output resembling the following:

{
  "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 The type that was exported
2 A listing of properties

如果资源有到其他资源的链接,则会有更多详细信息。

There are more details if your resources have links to other resources.

你还可以从 “_links” 集合中找到一个 “profile” 链接,当你检查一个集合资源时,如下例所示:

You can also find a profile link in the collection of _links when you examine a collection resource, as the following example shows:

{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/persons" 1
    },
    ... other links ...
    "profile" : {
      "href" : "http://localhost:8080/profile/persons" 2
    }
  },
  ...
}
1 This HAL document respresents the Person collection.
2 It has a profile link to the same URI for metadata.

同样`profile` 链接默认提供 ALPS。如果您向它提供一个 application/schema+jsonAccept header,则它将呈现 JSON Schema 表示。

Again, the profile link serves ALPS by default. If you supply it with an Accept header of application/schema+json, it renders the JSON Schema representation.