前情提要
在前篇提到了如何透過 Viper 來取得 config 檔與環境變數來組成我們的組態檔。
這篇我們會進一步討論,透過 Go 的強型別特性,取得組態物件,並處理巢狀的結構。
假想情境
假設今天我們要作一個金流服務,
後面可能會介接 PayPal、Strip 等等不同金流的服務,
那我的組態設定上可能就會有不同的階層關係
1 | { |
那麼問題來了
- 我應該怎麼取用這些組態 ?
- 可以直接透過
viper.Get("name")
取得值 - 但是每次都要用組態名稱字串取得值,其實是一個風險;
比如打錯字,很難有工具有效防範 - 所以我希望建立一個 type 去定義組態檔,並透過物件去存取,
這可以有效將寫死字串限定至一次。
- 可以直接透過
- 有了上述的方向後,另一個問題是巢狀解構的解析,
一般來說,我認為組態檔不應該有超過三層的深度,這次就用兩作為範例說明 - Viper 本身支援多種組態格式,本篇僅以
env
、json
、yaml
作範例說明 - 在上一篇提到,當存在環境變數時,環境變數的優先度應高於檔案
期待的結果
我們在啟動程式的時候,一次性將組態載入事先定義好的物件之中,
如果有環境變數,優先取用。
如果沒有環境變數,會讀開發者提供的組態檔(env 檔優先,也要能支援 json 或 yaml )
如果完全沒有組態,應該發出警告
定義 Type
首先建立我們的 Type
1 | type Config struct { |
接下來我們如果上一篇宣告 Of
方法用來取得組態
1 | // define instance |
此時我們要將組態載入,先考慮開發者環境的實體檔案
1 | func Load() { |
實作 env 使用的 config.env 檔案如下
1 | Version="1.10.1.yaml" |
修改 viper 相關設定
1 | // just for development environment |
實作 yml 使用的 config.yml 檔案如下
1 | Version: "1.10.1.yml" |
修改 viper 相關設定
1 | // just for development environment |
實作 json 使用的 config.json 檔案如下
1 | { |
修改 viper
1 | // just for development environment |
以上提供了幾種不同的 type
環境變數
我使用的環境變數如下
1 | STRIPE__ENABLE=true;STRIPE__No=678;VERSION=8.88.8;PAYPAL__ENABLE=false;PAYPAL__MERCHANT_NO=ENV9999 |
首先,我們知道環境變數並不像 json
或 yaml
檔一樣可以提供巢狀的結構,
這就與我們的需求有了衝突,好在 viper
提供了 BindEnv
的方法, 我們可以強制讓它建立出巢狀的結構,
如下:
1 | vp.BindEnv("VERSION") |
寫在後面,在查找資料的過程中,可以發現 viper 提供了兩個功能強大的方法,
SetEnvPrefix 與 SetEnvKeyReplacer ;
SetEnvPrefix 可以自動加上前綴,SetEnvKeyReplacer 可以將分隔符置換。
可惜在我的情境尚且用不到,未來再作研究。
參考
- Tutorial Series: How To Code in Go
- Go 语言中的 struct tag
- Configuring JSON struct fields
- 在 Go 語言使用 Viper 管理設定檔
(fin)