我编写了带有硬编码配置变量的中型Haskell应用程序(如Google OAuth ClientId& ClientSecret)。既然我正在为生产部署准备应用程序,我需要将所有这些配置变量从源代码移到:(a)环境变量,或(b)纯文本配置文件。
这里的代码目前看起来像是什么:
googleClientId :: T.Text
googleClientId = "redacted"
googleClientSecret :: T.Text
googleClientSecret = "redacted"
generateOAuthUserCode :: IO (OAuthCodeResponse)
generateOAuthUserCode = do
r <- asJSON =<< post "https://accounts.google.com/o/oauth2/device/code" ["client_id" := googleClientId, "scope" := ("email profile" :: T.Text)]
return $ r ^. responseBody
从环境变量(或配置文件)中获取googleClientId
和googleClientSecret
的最快/最简单方法是什么?我尝试了以下方法:
googleClientId :: T.Text
googleClientId = undefined
googleClientSecret :: T.Text
googleClientSecret = undefined
main :: IO()
main = do
googleClientId <- getEnv "GOOGLE_CLIENT_ID"
googleClientSecret <- getENV "GOOGLE_CLIENT_SECRET"
-- Start the main app, which internally will call generateOAuthUserCode at some point.
期望全局googleClientId
和googleClientSecret
将重新绑定,但我的编辑器立即开始显示警告&#34;绑定阴影现有绑定&#34;,表示Haskell正在创建一个新的绑定,而不是更改现有绑定。
所以,这里有两个问题:
编辑:以下方法如何?
以下方法怎么样?
outerFunc :: String -> String -> IO ()
outerFunc googleClientId googleClientSecret = do
-- more code comes here
where
generateOAuthUserCode :: IO (OAuthCodeResponse)
generateOAuthUserCode = do
r <- asJSON =<< post "https://accounts.google.com/o/oauth2/device/code" ["client_id" := googleClientId, "scope" := ("email profile" :: T.Text)]
return $ r ^. responseBody
-- more functions depending upon the config variables
答案 0 :(得分:4)
我认为您经常在代码库中依赖googleClientId
等全局变量。
在进入“技术债务”路线之前,您可能想尝试并至少估算Reader
方法的成本。无论如何,全局变量都是一种不好的做法,@ Casten提出了另一种重构方法。但既然你要求务实的帮助......
问题1:最快/最简单方式是使用皱眉unsafePerformIO
。像这样:
googleClientId = unsafePerformIO $ getEnv "GOOGLE_CLIENT_ID"
main = putStrLn googleClientId
这基本上可以让你忽略IO
的安全性,并将所需的值放入一个全局变量中,就像它是一个普通的字符串一样。请注意,如果环境变量不存在,getEnv
会崩溃。
问题2:人们不能在Haskell中“更新”变量。如果在嵌套范围中创建另一个具有相同名称的变量,则该绑定将遮蔽内部范围中的外部变量,从而保持外部绑定不变。这有点令人困惑,因此警告。