2017-08-25 56 views
6

我是一名Haskell初學者,目前正在使用wreq來製作一個圍繞api的簡單包裝。如果提供時間,我想發送一個if-modified-since標題。我按照以下方式這樣做。Haskell/Wreq - 對http請求的複雜類型簽名的建議

getResponse :: (FormatTime t, Exception e) => File -> Maybe t -> IO (Either e (Response L.ByteString)) 
getResponse file (Just t) = 
    let formattedTime = (B.pack . formatTime defaultTimeLocale rfc822DateFormat) t 
     opts = defaults & header "if-modified-since" .~ [formattedTime] 
    in try $ getWith opts $ buildUrl file 

getResponse file Nothing = try $ (get $ buildUrl file) 

我注意到304 (not modified)響應回來作爲例外,這樣是我使用Either類型的理由。我想爲可能使用此api包裝的人員提供可見性。

假設請求成功,我想將響應正文解析爲我的庫中定義的相應類型。如果在提出請求的服務器上發生了某些更改,則反序列化可能無法正常工作,因此我選擇使用Maybe類型來解決此問題。

getPayload :: FromJSON b => (Either e (Response L.ByteString)) -> Either e (Maybe b) 
getPayload (Left _) = return Nothing 
getPayload (Right a) = return $ fmap Just (^. responseBody) =<< asJSON a 

這些功能的特徵也開始像一個礙眼到我看來,東西在我的直覺告訴我有一個更好的方式,但我不確定。我做的一件事是做出另一個功能,把它們放在一起,希望它更容易使用。這是我計劃使用的功能來創建其他功能,以對個別資源進行更具體的請求。

getResource :: (Exception e, FormatTime t, FromJSON b) => File -> Maybe t -> IO (Either e (Maybe b)) 
getResource f t = getPayload <$> (getResponse f t) 

我現在不得不在處理http請求時處理3層結構。 IO,EitherMaybe。我是否讓這個過於複雜?從使用和可維護性的角度來看,我能做些什麼來減輕這種痛苦?我該如何改進?

+4

難道你不能將'e(可能b)'變成''或e'',其中'e'還可以攜帶關於反序列化失敗的信息? '也許b'與'Either()b'同構。 –

+2

我會考慮使用自定義數據類型'data ResourceResult b = Error e | NotModified |結果b'。圖書館總數和產品類型都很好,但是沒有任何風格:它們非常通用,不能傳達任何意義。最好使用具有適當名稱的自定義類型。 – chi

+0

謝謝你的建議@chi。我會牢記這一點。 –

回答

2

這可能不完全是你想要的,但asJSON有返回類型m (Response a),其中mMonadThrow。雖然MaybeMonadThrow實例,但Either e也是如此。這意味着你不要使用Maybe爲了處理如果有任何問題asJSON。在Either單子,而不是你可以「留」:

getPayload :: FromJSON b => Either SomeException (Response L.ByteString) 
         -> Either SomeException b 
getPayload = ((fmap (^. responseBody) . asJSON) =<<) 

顯然,這使一個附加的約束出錯的左側的類型,所以我不知道這是可以接受的。如果沒有,請留下評論。

+0

今晚我會嘗試這個,回到你身邊。 –

+0

在https://www.schoolofhaskell.com/user/commercial/content/exceptions-best-practices上閱讀了'MonadThrow'之後它看起來像MonadThrow會隱藏拋出的異常。我不希望發生這種情況,因爲如果異常是304響應代碼,那麼消費者需要知道,以便他們可以提供他們已緩存的數據。使用自定義類型的想法聽起來很有吸引力。 –

+1

@NickAcosta是的,自定義類型可能是你想要的,但說「MonadThrow」會隱藏異常是不正確的。'Maybe'是真的,因爲Nothing沒有拋出錯誤原因,但是對於'E',這個異常就在'Left'的情況下,並且可以用'catch'來處理。 –