2017-08-25 16 views
6

Tôi là người mới bắt đầu sử dụng Haskell và hiện đang sử dụng wreq để tạo một trình bao bọc đơn giản xung quanh một api. Tôi muốn gửi tiêu đề if-modified-since nếu được cung cấp cùng một lúc. Tôi đang làm như vậy theo cách sau.Haskell/Wreq - Lời khuyên về chữ ký phức tạp cho các yêu cầu 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) 

tôi nhận thấy rằng 304 (not modified) phản ứng đang trở lại như trường hợp ngoại lệ như vậy đó là biện minh của tôi cho việc sử dụng các loại Either. Tôi muốn cung cấp khả năng hiển thị lỗi cho những người có thể sử dụng trình bao bọc api này.

Giả sử yêu cầu thành công, tôi muốn phân tích cú pháp nội dung phản hồi thành một loại tương ứng được xác định trong thư viện của tôi. Có một cơ hội deserialization có thể không hoạt động chính xác nếu một cái gì đó thay đổi trên máy chủ tôi đang yêu cầu để vì vậy tôi đã chọn để sử dụng loại Maybe để giải thích cho việc này.

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 

Chữ ký của các chức năng này bắt đầu có vẻ giống như tôi, điều gì đó trong ruột cho tôi biết có cách tốt hơn nhưng tôi không chắc chắn. Một điều tôi đã làm là tạo ra một chức năng khác để đặt chúng cùng với hy vọng nó sẽ dễ sử dụng hơn. Đây là hàm tôi định sử dụng để tạo các hàm khác để thực hiện các yêu cầu cụ thể hơn đối với tài nguyên cá nhân.

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

Bây giờ tôi phải xử lý 3 lớp cấu trúc khi xử lý yêu cầu http. IO, EitherMaybe. Tôi có làm quá phức tạp không? Tôi có thể làm gì để giảm bớt nỗi đau khi làm việc với quan điểm sử dụng và bảo trì? Làm thế nào tôi có thể cải thiện điều này?

+4

Bạn không thể làm phẳng 'Hoặc e (Có thể b) 'thành' Hoặc e b', trong đó 'e' cũng có thể mang thông tin về lỗi thất bại? 'Có thể b' là đẳng cấu cho' Hoặc() b'. –

+2

Tôi muốn xem xét sử dụng kiểu dữ liệu tùy chỉnh 'data ResourceResult b = Error e | NotModified | Kết quả b'. Tổng thư viện và các loại sản phẩm là tốt, nhưng không hương vị: chúng rất chung chung đến mức chúng không truyền đạt ý nghĩa. Tốt hơn là nên sử dụng loại tùy chỉnh có tên phù hợp, gợi nhiều gợi ý. – chi

+0

Cảm ơn bạn đã giới thiệu @chi này. Tôi sẽ ghi nhớ điều này. –

Trả lời

2

Đây có thể không hoàn toàn là điều bạn muốn nhưng asJSON có loại trả lại m (Response a), trong đó mMonadThrow. Trong khi Maybe là một phiên bản MonadThrow, thì đó là Either e. Điều này có nghĩa là bạn không để sử dụng Maybe để xử lý nếu có sự cố với asJSON. Bạn có thể 'ở lại' trong Either đơn nguyên thay vì:

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

Rõ ràng, điều này đặt thêm một ràng buộc vào loại lỗi ở phía bên trái, vì vậy tôi không chắc chắn rằng đây là chấp nhận được. Nếu không, xin vui lòng để lại một bình luận.

+0

Tôi sẽ cố gắng tối nay và liên hệ lại với bạn. –

+0

Sau khi thực hiện một số đọc trên 'MonadThrow' tại https://www.schoolofhaskell.com/user/commercial/content/exceptions-best-practices Dường như MonadThrow sẽ ẩn ngoại lệ bị ném. Tôi không muốn điều này xảy ra vì nếu ngoại lệ là mã phản hồi 304 mà người tiêu dùng sẽ cần phải biết để họ có thể phân phát dữ liệu nào họ đã lưu trong bộ nhớ cache. Ý tưởng sử dụng loại tùy chỉnh có vẻ hấp dẫn. –

+1

@NickAcosta Có, một loại tùy chỉnh có thể là những gì bạn muốn, nhưng nó hầu như không chính xác để nói rằng 'MonadThrow' sẽ ẩn ngoại lệ.Điều này đúng với 'Maybe', bởi vì' Nothing' ném đi nguyên nhân lỗi, nhưng đối với 'Either e', ngoại lệ nằm ngay trong trường hợp' Left', và có thể được xử lý bằng 'catch'. –

Các vấn đề liên quan