Metadata

本節詳細說明 Spring Data REST 應用程式所提供的各種形式的 metadata。

應用程式層級設定檔語意 (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 為每個匯出的 repository 提供 ALPS 文件。它包含有關 RESTful 轉換和每個 repository 的屬性的資訊。

在 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 才能找到每個資源 metadata 的連結。

如果您導覽到 /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 文件不同,後者具有 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 以取得 metadata 的設定檔連結。

同樣,預設情況下,profile 連結會提供 ALPS。但是,如果您使用 Accept 標頭,它可以提供 application/alps+json

超媒體控制類型

ALPS 顯示每個超媒體控制的類型。它們包括

表 1. ALPS 類型
類型 描述

SEMANTIC

狀態元素(例如 HTML.SPANHTML.INPUT 等)。

SAFE

觸發安全、等冪狀態轉換的超媒體控制(例如 GETHEAD)。

IDEMPOTENT

觸發不安全、等冪狀態轉換的超媒體控制(例如 PUTDELETE)。

UNSAFE

觸發不安全、非等冪狀態轉換的超媒體控制(例如 POST)。

在先前顯示的表示法章節中,應用程式中的資料位元被標記為 SEMANTICaddress 欄位是一個連結,涉及安全的 GET 進行擷取。因此,它被標記為 SAFE。超媒體操作本身會對應到上表所示的類型。

具有投影的 ALPS

如果您定義任何投影,它們也會列在 ALPS metadata 中。假設我們也定義了 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 metadata 中。若要執行此操作,請建立 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 支援的另一種形式的 metadata。根據他們的網站,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.dev.org.tw/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 以取得 metadata 的設定檔連結。

同樣,預設情況下,profile 連結會提供 ALPS。如果您為其提供 application/schema+jsonAccept 標頭,它會呈現 JSON Schema 表示法。