<div>
<a class="article-series-header" href="javascript:void(0);">該文章是系列文章之一</a>
<div>
<div>
• 介紹 RAML – RESTful API 建模語言
<br>
• 使用資源類型和特性消除 RAML 中的冗餘
<br>
<div>
• 使用包含、庫、覆蓋和擴展模塊化 RAML (當前文章)
</div>
• 使用註釋定義自定義 RAML 屬性
<br>
</div>
<!-- end of article series inner -->
</div>
<!-- .article-series-links -->
</div>
1. 引言
在之前關於 RAML – RESTful API 建模語言的兩篇文章中,我們介紹了基本語法,包括數據類型和 JSON 模式的使用,並展示瞭如何通過將常見模式提取為 資源類型 和 特性 來簡化 RAML 定義。
在本文中,我們將演示 如何將您的 RAML API 定義分解為模塊,利用 包含、庫、覆蓋 和 擴展。
2. 我們的API
本文檔將重點介紹我們API中與名為Foo的實體類型相關的部分。
以下是構成我們API的資源:
- GET /api/v1/foos
- POST /api/v1/foos
- GET /api/v1/foos/{fooId}
- PUT /api/v1/foos/{fooId}
- DELETE /api/v1/foos/{fooId}
3. 包含 (Includes)
一個 包含 (include) 的目的是通過將屬性值放置在外部文件中,對複雜的 RAML 定義中的屬性值進行模塊化。
我們在指定數據類型和示例時,這些示例的屬性值在 API 中被重複使用,這與我們之前簡要提及的 包含 (includes) 的使用方式相同。
3.1. 常用用法與語法
<em !include</em> 標籤接受一個參數:外部文件(包含屬性值)的路徑。該路徑可以是絕對 URL、相對於根 RAML 文件的路徑,或相對於包含文件的路徑。
路徑以正斜槓 (/) 開頭,表示相對於根 RAML 文件的路徑;而沒有以正斜槓開頭的路徑則表示相對於包含文件的路徑。
上述邏輯的推論是,包含的文件本身也可能包含其他的 <em !include</em> 指令。
以下是一個展示了 <em !include</em> 標籤三種使用方式的示例:
#%RAML 1.0
title: Baeldung Foo REST Services API
...
types: !include /types/allDataTypes.raml
resourceTypes: !include allResourceTypes.raml
traits: !include http://foo.com/docs/allTraits.raml3.2. 帶有類型片段 (Typed Fragments)
與其將所有 類型, 資源類型或特質分別放在各自的 包含文件中,您還可以使用一種特殊類型的 包含文件,即 帶有類型片段,將這些構造體分解為多個 包含文件,為每個 類型, 資源類型或特質指定不同的文件。
您還可以使用 帶有類型片段來定義 用户文檔項, 命名示例, 註釋, 庫, 覆蓋和擴展。 我們稍後在本文中將介紹 覆蓋和擴展的使用。
雖然使用 包含文件(特別是 帶有類型片段)並非必需,但該 包含文件的第一行可以是一個 RAML 片段標識符,格式如下:
#%RAML 1.0 <fragment-type>以下是翻譯後的內容:
例如,一個 類型片段文件中第一行,用於一個 trait 將是:
#%RAML 1.0 Trait如果使用片段標識符,則該文件的內容必須僅包含指定片段類型的有效 RAML。
下面我們首先來看 API 的 traits 部分的一個片段:
traits:
- hasRequestItem:
body:
application/json:
type: <<typeName>>
- hasResponseItem:
responses:
200:
body:
application/json:
type: <<typeName>>
example: !include examples/<<typeName>>.json為了使用類型片段</em lang>模塊化這一部分內容,我們首先按照以下方式重寫特質</em lang>部分:
traits:
- hasRequestItem: !include traits/hasRequestItem.raml
- hasResponseItem: !include traits/hasResponseItem.raml我們隨後將編寫 類型片段 文件 hasRequestItem.raml:
#%RAML 1.0 Trait
body:
application/json:
type: <<typeName>>類型片段文件 hasResponseItem.raml 如下所示:
#%RAML 1.0 Trait
responses:
200:
body:
application/json:
type: <<typeName>>
example: !include /examples/<<typeName>>.json4. 庫 (Libraries)
RAML 的 庫 (libraries) 可以用於模塊化任意數量和組合的 數據類型 (data types)、安全方案 (security schemes)、資源類型 (resource types)、特性 (traits) 和 註解 (annotations)。
4.1. 定義一個庫
雖然通常在外部文件中定義,然後作為include引用,但library也可以內聯定義。 包含在外部文件中的library也可以引用其他library。
與常規的include或typed fragment不同,包含在外部文件中的library必須聲明頂層元素名稱。
讓我們將我們的traits部分重寫為一個library文件:
#%RAML 1.0 Library
# This is the file /libraries/traits.raml
usage: This library defines some basic traits
traits:
hasRequestItem:
usage: Use this trait for resources whose request body is a single item
body:
application/json:
type: <<typeName>>
hasResponseItem:
usage: Use this trait for resources whose response body is a single item
responses:
200:
body:
application/json:
type: <<typeName>>
example: !include /examples/<<typeName>>.json4.2. 使用庫
庫通過頂層 uses 屬性應用,其值為一個或多個對象,其屬性名稱是 library 名稱,其屬性值構成 libraries 的內容。
在為我們的 security schemes、data types、resource types 和 traits 創建了 libraries 後,我們可以將這些 libraries 應用到根 RAML 文件上:
#%RAML 1.0
title: Baeldung Foo REST Services API
uses:
mySecuritySchemes: !include libraries/security.raml
myDataTypes: !include libraries/dataTypes.raml
myResourceTypes: !include libraries/resourceTypes.raml
myTraits: !include libraries/traits.raml4.3. 引用庫
一個 庫 通過連接 庫 的名稱、一個點 (.) 和要引用的元素(例如數據類型、資源類型、特性等)來引用。
你可能還記得我們之前文章中,我們如何使用我們定義的 特性 來重構我們的 資源類型。 下面的示例展示瞭如何將我們的“item” 資源類型 編寫為 庫,如何將 特性 庫 文件(如上所示)包含在新的 庫 中,以及如何通過在 特性 名稱前加上其 庫 命名限定符 (“myTraits”) 來引用 特性:
#%RAML 1.0 Library
# This is the file /libraries/resourceTypes.raml
usage: This library defines the resource types for the API
uses:
myTraits: !include traits.raml
resourceTypes:
item:
usage: Use this resourceType to represent any single item
description: A single <<typeName>>
get:
description: Get a <<typeName>> by <<resourcePathName>>
is: [ myTraits.hasResponseItem, myTraits.hasNotFound ]
put:
description: Update a <<typeName>> by <<resourcePathName>>
is: [ myTraits.hasRequestItem, myTraits.hasResponseItem, myTraits.hasNotFound ]
delete:
description: Delete a <<typeName>> by <<resourcePathName>>
is: [ myTraits.hasNotFound ]
responses:
204:5. 覆蓋層和擴展
覆蓋層和擴展是定義在外部文件中使用的模塊,用於擴展 API。覆蓋層用於擴展 API 的非行為性方面,例如描述、用法説明和用户文檔項,而擴展用於擴展或覆蓋 API 的行為性方面。
與包含不同,包含文件通過引用其他 RAML 文件應用於代碼中,覆蓋層和擴展文件必須包含一個引用(通過頂層 masterRef 屬性)指向其主文件,該主文件可以是有效的 RAML API 定義或另一個覆蓋層或擴展文件,該文件將被應用到其中。
5.1. 定義
overlay 或 extension 文件的第一行必須按照以下格式進行:
RAML 1.0 Overlay
第一行覆蓋文件必須採用類似格式:
RAML 1.0 Extension
5.2. 使用限制
在使用一組疊加和/或擴展時,所有這些文件必須指向同一個主 RAML 文件。此外,RAML 處理工具通常期望主 RAML 文件和所有疊加和擴展文件都具有相同的文件擴展名(例如“.raml”)。
5.3. 疊加使用的場景
疊加 (overlays) 的設計理念是提供一種將接口與實現分離的機制,從而允許 RAML 規範中更注重人機交互的部分更頻繁地更改或擴展,而 API 的核心行為保持穩定。
一個常見的疊加使用場景是在多種語言中提供用户文檔和其他描述性元素。 讓我們重寫 API 的標題並添加一些用户文檔項:
#%RAML 1.0
title: API for REST Services used in the RAML tutorials on Baeldung.com
documentation:
- title: Overview
- content: |
This document defines the interface for the REST services
used in the popular RAML Tutorial series at Baeldung.com.
- title: Copyright
- content: Copyright 2016 by Baeldung.com. All rights reserved.以下是如何為本部分定義西班牙語覆蓋層:
#%RAML 1.0 Overlay
# File located at (archivo situado en):
# /overlays/es_ES/documentationItems.raml
masterRef: /api.raml
usage: |
To provide user documentation and other descriptive text in Spanish
(Para proporcionar la documentación del usuario y otro texto descriptivo
en español)
title: |
API para servicios REST utilizados en los tutoriales RAML
en Baeldung.com
documentation:
- title: Descripción general
- content: |
Este documento define la interfaz para los servicios REST
utilizados en la popular serie de RAML Tutorial en Baeldung.com.
- title: Derechos de autor
- content: |
Derechos de autor 2016 por Baeldung.com.
Todos los derechos reservados.疊加在另一個常見用法是外部化標註元數據,這本質上是一種向 API 添加非標準構造的方式,以便為 RAML 處理器(如測試和監控工具)提供鈎子。
5.4. 擴展功能的用途
如名稱所示,擴展功能 (extensions) 用於通過添加新的行為和/或修改 API 現有行為來擴展 API。 從面向對象編程世界的類比來看,這類似於子類擴展超類,其中子類可以添加新的方法和/或覆蓋現有方法。 擴展功能還可以擴展 API 的非功能性方面。
一個 擴展功能 (extension) 可以用於定義僅對特定用户(例如管理員或已分配特定角色的用户)可訪問的額外資源。 另一個 擴展功能 (extension) 也可以用於為 API 的新版本添加功能。
下面是一個 擴展功能 (extension),它覆蓋了我們 API 的版本,並添加了在先前版本中不可用的資源:
#%RAML 1.0 Extension
# File located at:
# /extensions/en_US/additionalResources.raml
masterRef: /api.raml
usage: This extension defines additional resources for version 2 of the API.
version: v2
/foos:
/bar/{barId}:
get:
description: |
Get the foo that is related to the bar having barId = {barId}
typeName: Foo
queryParameters:
barId?: integer
typeName: Foo
is: [ hasResponseItem ]以下是該 擴展的西班牙語版本 覆蓋層:
#%RAML 1.0 Overlay
# Archivo situado en:
# /overlays/es_ES/additionalResources.raml
masterRef: /api.raml
usage: |
Se trata de un español demasiado que describe los recursos adicionales
para la versión 2 del API.
version: v2
/foos:
/bar/{barId}:
get:
description: |
Obtener el foo que se relaciona con el bar tomando barId = {barId}值得注意的是,儘管我們在本示例中使用了 覆蓋層 來處理西班牙語的覆蓋設置,因為這不會修改 API 的任何行為,我們也可以將此模塊定義為 擴展。考慮到其目的在於覆蓋位於其之上的英語 擴展 中的屬性,將其定義為 擴展 可能會更合適。
6. 結論
在本教程中,我們介紹了多種技術,以使 RAML API 定義更模塊化,通過將常見構造體分離到外部文件。
首先,我們展示了 RAML 中的 include 功能如何用於將單個複雜屬性值重構為可重用外部文件模塊,這些模塊被稱為 類型片段。 接下來,我們演示瞭如何使用 include 功能將某些元素的集合外部化為可重用的 庫。 最後,我們通過使用 覆蓋 和 擴展 來擴展 API 的行為和非行為方面。
要了解更多關於 RAML 模塊化技術的知識,請訪問 RAML 1.0 規範。