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 文档的媒体类型为 application/alps+json。这与前一个 JSON 文档不同,前一个 JSON 的媒体类型为 application/hal+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 为每个超媒体控件显示类型。它们包括:

Table 1. ALPS types
Type Description

SEMANTIC

状态元素(例如 HTML.SPANHTML.INPUT 等)。

SAFE

触发安全幂等状态转换的超媒体控件(例如 GETHEAD)。

IDEMPOTENT

触发不安全幂等状态转换的超媒体控件(例如 PUTDELETE)。

UNSAFE

触发不安全非幂等状态转换的超媒体控件(例如 POST)。

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

ALPS with Projections

如果您定义任何投影,它们也列在 ALPS 元数据中。假设我们还定义了 inlineAddressnoAddresses,它们将出现在相关的操作内。(请参见 “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。它渲染 addressfirstName`和 `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+jsonAccept header,则它将呈现 JSON Schema 表示。