namespace example.weather

/// Provides weather forecasts.
@paginated(inputToken: "nextToken", outputToken: "nextToken", pageSize: "pageSize")
service Weather {
version: "2006-03-01"
resources: [
City
]
operations: [
GetCurrentTime
]
}

resource City {
identifiers: { cityId: CityId }
properties: { coordinates: CityCoordinates }
read: GetCity
list: ListCities
resources: [
Forecast
]
}

resource Forecast {
identifiers: { cityId: CityId }
properties: { chanceOfRain: Float }
read: GetForecast
}

//"pattern" is a trait.
@pattern("^[A-Za-z0-9 ]+$")
string CityId

@readonly
operation GetCity {
input := for City {
//"cityId" provides the identifier for the resource and
// has to be marked as required.
@required
$cityId
}

output := for City {
//"required" is used on output to indicate if the service
// will always provide a value for the member.
//"notProperty" indicates that top-level input member "name"
// is not bound to any resource property.
@required
@notProperty
name: String

@required
$coordinates
}

errors: [
NoSuchResource
]
}

// This structure is nested within GetCityOutput.
structure CityCoordinates {
@required
latitude: Float

@required
longitude: Float
}

//"error" is a trait that is used to specialize
// a structure as an error.
@error("client")
structure NoSuchResource {
@required
resourceType: String
}

// The paginated trait indicates that the operation may
// return truncated results.
@readonly
@paginated(items: "items")
operation ListCities {
input := {
nextToken: String
pageSize: Integer
}

output := {
nextToken: String

@required
items: CitySummaries
}
}

// CitySummaries is a list of CitySummary structures.
list CitySummaries {
member: CitySummary
}

// CitySummary contains a reference to a City.
@references([
{
resource: City
}
])
structure CitySummary {
@required
cityId: CityId

@required
name: String
}

@readonly
operation GetCurrentTime {
output := {
@required
time: Timestamp
}
}

@readonly
operation GetForecast {
input := for Forecast {
//"cityId" provides the only identifier for the resource since
// a Forecast doesn't have its own.
@required
$cityId
}

output := for Forecast {
$chanceOfRain
}
}

將其分成單獨的部分,我們可以在頂部看到代碼的控制部分:

$version: "2"

下面是實質性代碼:

namespace example.weather

/// Provides weather forecasts.
@paginated(inputToken: "nextToken", outputToken: "nextToken", pageSize: "pageSize")
service Weather {
version: "2006-03-01"
resources: [
City
]
operations: [
GetCurrentTime
]
}

resource City {
identifiers: { cityId: CityId }
properties: { coordinates: CityCoordinates }
read: GetCity
list: ListCities
resources: [
Forecast
]
}

resource Forecast {
identifiers: { cityId: CityId }
properties: { chanceOfRain: Float }
read: GetForecast
}

這里我們有服務的定義(及其分頁)以及所利用的資源以及對這些資源采取的操作。

//"pattern" is a trait.
@pattern("^[A-Za-z0-9 ]+$")
string CityId

@readonly
operation GetCity {
input := for City {
//"cityId" provides the identifier for the resource and
// has to be marked as required.
@required
$cityId
}

output := for City {
//"required" is used on output to indicate if the service
// will always provide a value for the member.
//"notProperty" indicates that top-level input member "name"
// is not bound to any resource property.
@required
@notProperty
name: String

@required
$coordinates
}

errors: [
NoSuchResource
]
}

// This structure is nested within GetCityOutput.
structure CityCoordinates {
@required
latitude: Float

@required
longitude: Float
}

//"error" is a trait that is used to specialize
// a structure as an error.
@error("client")
structure NoSuchResource {
@required
resourceType: String
}

// The paginated trait indicates that the operation may
// return truncated results.
@readonly
@paginated(items: "items")
operation ListCities {
input := {
nextToken: String
pageSize: Integer
}

output := {
nextToken: String

@required
items: CitySummaries
}
}

// CitySummaries is a list of CitySummary structures.
list CitySummaries {
member: CitySummary
}

// CitySummary contains a reference to a City.
@references([
{
resource: City
}
])
structure CitySummary {
@required
cityId: CityId

@required
name: String
}

@readonly
operation GetCurrentTime {
output := {
@required
time: Timestamp
}
}

@readonly
operation GetForecast {
input := for Forecast {
//"cityId" provides the only identifier for the resource since
// a Forecast doesn't have its own.
@required
$cityId
}

output := for Forecast {
$chanceOfRain
}
}

從這里開始,我們有一系列特征定義和嵌套結構,允許在模型內排列輸出和功能,從而更好地控制基本輸出和功能。查看此代碼,您可以看到特征定義如何解鎖功能控制。本質上,特征允許在不從根本上改變底層實體的情況下約束和格式化數據和服務。

Smithy的優點和缺點

考慮到這一點,使用像 Smithy 這樣的東西有什么優點和缺點?

優點

對于大多數用戶來說,采用 Smithy 的最大好處是它與協議無關。并非所有開發都經過提前考慮,您今天使用的協議永遠都是正確的。采用像 Smithy 這樣的解決方案,您可以為當前的工作創建模型,這些模型可以隨著新的開發而變形、改變和改變。這為您提供了很大的靈活性,最終使您的開發擺脫了嚴格的限制。

專注于模型驅動系統可以實現機器和人類的高效可讀性。模型可以從一個系統移植到另一個系統,并轉換為其他格式和類型,從而將底層系統從外部控制的負擔中解放出來。模型也很容易比較,可以實現更好的自動化,從而提高效率。

Smithy 也是開源的,這是一個巨大的好處!與協議無關的解決方案很棒,但是當這種解決方案的開發也與源代碼控制解耦時,可能會使其關閉并集中控制,這會使其開發和迭代速度更快。 Smithy 是一個可以獨立完成很多事情的工具,但從長遠來看,將其開放給社區開發和迭代可以使其成為一些非常令人驚奇的事情的平臺!

缺點

雖然 Smithy 在其基于模型的系統上做了很多出色的工作,但它提供代碼生成作為一個重要功能。事實上,代碼生成仍然存在重大問題,即使這里提供了大量的修復和系統,這些問題也不會消失。使用 Smithy 進行代碼生成通常很有效,但與任何代碼生成工具一樣,99% 的情況下,輸出都可以,但這 1% 意味著您需要非常密切地關注并投入資源進行審查,這削弱了從代碼生成中獲得的一些好處。

Smithy 功能齊全。在某些情況下,這可能是負面的。如果您希望構建一些非常簡單的東西,只有少數人與之交互,那么為其他觀看者進行投影或為多個團隊創建模型訪問規則的想法可能不適合您。在這種情況下,讓史密斯加入的成本可能不合理。與任何事情一樣,您應該考慮 Smithy 是您需要使用的東西還是您只想使用的東西。

最后,需要簡單說明的是,這是亞馬遜開發的產品。雖然這當然不應該是采用或不采用工具的唯一原因,但該項目的長期維護和健康與亞馬遜本身的長期維護和健康息息相關。雖然亞馬遜看起來不會很快走向任何地方,但對于那些在網絡開發領域工作了很長一段時間的人來說,在其首次發布十年或二十年之后,企業發展陷入困境和崩潰的故事比比皆是,而這個肯定應該是一個考慮因素。即使產品是開源的,開源并不意味著永久開發,并且在任何特定時刻都可能會認為 Smithy 不值得花費時間或資源。

開源軟件也有轉變為更多商業許可證的趨勢。從版本 2.15 開始,Buoyant Enterprise for Linkerd 宣布 Linkerd 將不再生成開源穩定版本。截至 2024 年,Redis 有爭議地放棄了 BSD 許可證,引起社區許多人的嚴重擔憂。不幸的是,這些故事很常見,并說明了像 Smithy 這樣的解決方案的一個巨大問題——它適合開源框架,直到它不適合,而這種轉變可能會產生巨大的影響。

 結論

最終,對于采用強大的基于模型的解決方案的系統來說,Smithy 是一個不錯的選擇。雖然它對于所有實現來說可能都太重了,但它的靈活性和可擴展性使其成為許多情況下可靠的價值主張。

原文鏈接:https://nordicapis.com/overview-of-smithy-an-api-description-language-from-amazon/

上一篇:

掌握合約優先API開發:關鍵策略和優勢

下一篇:

.NET Core Web API + Vue By Linux and Windows 部署方案知識點總結
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費