元数据

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

应用程序级概要语义 (ALPS)

ALPS 是一种用于定义应用程序级语义简单描述的数据格式,其复杂性类似于 HTML 微格式。ALPS 文档可用作概要文件,以解释具有应用程序无关媒体类型(如 HTML、HAL、Collection+JSON、Siren 等)的文档的应用程序语义。这增加了概要文件文档跨媒体类型的可重用性。
— M. Admundsen / L. Richardson / M. Foster
https://tools.ietf.org/html/draft-amundsen-richardson-foster-alps-00

Spring Data REST 为每个导出的资源库提供一个 ALPS 文档。它包含有关 RESTful 转变和每个资源库的属性的信息。

在 Spring Data REST 应用程序的根目录中是一个概要链接。假设您有一个同时包含persons和相关addresses的应用程序,则根文档如下所示:

{
  "_links" : {
    "persons" : {
      "href" : "https://127.0.0.1:8080/persons"
    },
    "addresses" : {
      "href" : "https://127.0.0.1:8080/addresses"
    },
    "profile" : {
      "href" : "https://127.0.0.1:8080/profile"
    }
  }
}

概要链接(如RFC 6906中定义)是包含应用程序级详细信息的地方。ALPS 草案规范旨在定义特定的概要格式,我们将在本节后面探讨。

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

{
  "_links" : {
    "self" : {
      "href" : "https://127.0.0.1:8080/profile"
    },
    "persons" : {
      "href" : "https://127.0.0.1:8080/profile/persons"
    },
    "addresses" : {
      "href" : "https://127.0.0.1:8080/profile/addresses"
    }
  }
}
在根级别,profile是一个单个链接,不能提供多个应用程序概要。这就是为什么您必须导航到/profile才能找到每个资源元数据的链接。

如果您导航到/profile/persons并查看Person资源的概要数据,您会看到类似于以下示例的内容:

{
  "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" : "https://127.0.0.1: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 namepersons,这表示(因为它为复数)应将 POST 应用于整个集合,而不是单个person
4 typeUNSAFE,因为此操作可以更改系统状态。
5 rt#person-representation,这表示返回的资源类型将是Person资源。
此 JSON 文档的媒体类型为application/alps+json。这与之前的 JSON 文档不同,之前的 JSON 文档的媒体类型为application/hal+json。这些格式不同,并受不同规范管辖。

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

{
  "_links" : {
    "self" : {
      "href" : "https://127.0.0.1:8080/persons" (1)
    },
    ... other links ...
    "profile" : {
      "href" : "https://127.0.0.1:8080/profile/persons" (2)
    }
  },
  ...
}
1 此 HAL 文档表示Person集合。
2 它有一个指向相同元数据 URI 的profile链接。

同样,默认情况下,profile链接提供 ALPS。但是,如果您使用Accept标头,它可以提供application/alps+json

超媒体控制类型

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

表 1. ALPS 类型
类型 描述

SEMANTIC

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

SAFE

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

IDEMPOTENT

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

UNSAFE

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

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

带投影的 ALPS

如果您定义任何投影,它们也会列在 ALPS 元数据中。假设我们还定义了inlineAddressnoAddresses,它们将出现在相关的操作中。(有关这两个投影的定义和讨论,请参见“投影”)。也就是说,**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。它呈现addressfirstNamelastName。在投影内呈现的关系会导致内联包含数据字段。
3 noAddresses提供包含firstNamelastName的子集。

有了所有这些信息,客户端不仅可以推断出可用的 RESTful 转变,而且在某种程度上还可以推断出与后端交互所需的数据元素。

向您的 ALPS 描述添加自定义详细信息

您可以创建出现在 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" : "https://127.0.0.1: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 具有以下优点:

  • 描述您现有的数据格式

  • 清晰、易于人类和机器阅读的文档

  • 完整的结构验证,可用于自动化测试和验证客户端提交的数据

上一节所示,您可以从根 URI 导航到profile链接来访问此数据。

{
  "_links" : {
    "self" : {
      "href" : "https://127.0.0.1:8080/profile"
    },
    "persons" : {
      "href" : "https://127.0.0.1:8080/profile/persons"
    },
    "addresses" : {
      "href" : "https://127.0.0.1:8080/profile/addresses"
    }
  }
}

这些链接与前面显示的相同。要检索 JSON Schema,您可以使用以下Accept标头调用它们:application/schema+json

在这种情况下,如果您运行curl -H 'Accept:application/schema+json' 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.fullstack.org.cn/draft-04/schema#"
}
1 导出的类型
2 属性列表

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

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

{
  "_links" : {
    "self" : {
      "href" : "https://127.0.0.1:8080/persons" (1)
    },
    ... other links ...
    "profile" : {
      "href" : "https://127.0.0.1:8080/profile/persons" (2)
    }
  },
  ...
}
1 此 HAL 文档表示Person集合。
2 它有一个指向相同元数据 URI 的profile链接。

同样,profile链接默认情况下提供ALPS。如果您使用Accept标头application/schema+json,它将呈现 JSON Schema 表示。