元資料

本節詳細介紹了基於 Spring Data REST 的應用所提供的各種元資料形式。

應用級配置檔案語義 (ALPS)

ALPS 是一種資料格式,用於定義應用級語義的簡單描述,其複雜性與 HTML microformats 類似。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 應用的根目錄有一個 profile 連結。假設你有一個包含 persons 和相關 addresses 的應用,根文件如下所示

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

profile 連結,如 RFC 6906 中定義的那樣,是包含應用級詳細資訊的地方。ALPS 草案規範 旨在定義一種特定的配置檔案格式,我們將在本節後面進行探討。

如果你導航到 localhost:8080/profile 的 profile 連結,你會看到類似以下內容

{
  "_links" : {
    "self" : {
      "href" : "https://:8080/profile"
    },
    "persons" : {
      "href" : "https://:8080/profile/persons"
    },
    "addresses" : {
      "href" : "https://:8080/profile/addresses"
    }
  }
}
在根級別,profile 是一個單一連結,無法提供多個應用配置檔案。這就是為什麼你必須導航到 /profile 來查詢每個資源的元資料的連結。

如果你導航到 /profile/persons 並檢視 Person 資源的 profile 資料,你會看到類似以下示例的內容

{
  "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://: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://:8080/persons" (1)
    },
    ... other links ...
    "profile" : {
      "href" : "https://: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://: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 應用的核心)支援 locale,這意味著你可以捆綁包含不同訊息的多個屬性檔案。

JSON Schema

JSON Schema 是 Spring Data REST 支援的另一種元資料形式。根據其網站所述,JSON Schema 具有以下優點

  • 描述你現有資料格式

  • 清晰、人類可讀和機器可讀的文件

  • 完整的結構驗證,對於自動化測試和驗證客戶端提交的資料很有用

上一節所示,你可以透過從根 URI 導航到 profile 連結來獲取此資料。

{
  "_links" : {
    "self" : {
      "href" : "https://:8080/profile"
    },
    "persons" : {
      "href" : "https://:8080/profile/persons"
    },
    "addresses" : {
      "href" : "https://: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.org/draft-04/schema#"
}
1 匯出的型別
2 屬性列表

如果你的資源連結到其他資源,會有更多詳細資訊。

當你檢視一個集合資源時,你還可以在 _links 集合中找到一個 profile 連結,如下例所示

{
  "_links" : {
    "self" : {
      "href" : "https://:8080/persons" (1)
    },
    ... other links ...
    "profile" : {
      "href" : "https://:8080/profile/persons" (2)
    }
  },
  ...
}
1 此 HAL 文件表示 Person 集合。
2 它有一個指向相同 URI 的 profile 連結,用於元資料。

同樣,預設情況下,profile 連結提供 ALPS。如果你向其提供 application/schema+jsonAccept,它會渲染 JSON Schema 表示。