2015-06-24 15 views
7

Tôi đang làm theo hướng dẫn này http://www.parsonsmatt.org/programming/2015/06/07/servant-persistent.html để tạo API thông qua người hầu. Tôi cũng muốn tùy chỉnh máy chủ để phục vụ các tệp tĩnh nhưng không thể tìm thấy cách để thực hiện nó.Cung cấp các tệp tĩnh với Servant/Wai

Tôi đang sử dụng công cụ xây dựng stack.

tôi sửa đổi chạy các tập tin Main.hs để bao gồm static (run port $ static $ logger $ app cfg) và tôi nhập khẩu Network.Wai.Middleware.Static (static). Tôi cũng đã thêm wai-middleware-static >=0.7.0 && < 0.71 vào tệp cabal của mình.

Khi tôi chạy stack build tôi nhận được: (Cập nhật:. Phần này là hoàn toàn lỗi của tôi tôi đã thêm các gói vào file cabal sai .. què Nhập công trình Network.Wai.Middleware.Static và giao bóng. . file tĩnh Rời bỏ lỗi dưới đây trong trường hợp bất cứ ai tìm kiếm nó và tìm thấy nó hữu ích)

Could not find module ‘Network.Wai.Middleware.Static’ 
Perhaps you meant 
    Network.Wai.Middleware.Gzip (from [email protected]_GpotceEdscHD6hq9p0wPOJ) 
    Network.Wai.Middleware.Jsonp (from [email protected]_GpotceEdscHD6hq9p0wPOJ) 
    Network.Wai.Middleware.Local (from [email protected]_GpotceEdscHD6hq9p0wPOJ) 

Tiếp theo, tôi đã cố gắng sử dụng đầy tớ của serveDirectory như sau (giản thể):.

type API = "users" :> Get '[JSON] [Person] 
      :<|> "static" :> Raw 
server = createPerson :<|> serveDirectory "/static" 

tôi nhận được lỗi này:

Couldn't match type ‘IO’ with ‘EitherT ServantErr IO’ 
arising from a functional dependency between: 
    constraint ‘Servant.Server.Internal.Enter.Enter 
       (IO Network.Wai.Internal.ResponseReceived) 
       (AppM :~> EitherT ServantErr IO) 
       (IO Network.Wai.Internal.ResponseReceived)’ 
    arising from a use of ‘enter’ 
    instance ‘Servant.Server.Internal.Enter.Enter 
       (m a) (m :~> n) (n a)’ 
    at <no location info> 
In the expression: enter (readerToEither cfg) server 
In an equation for ‘readerServer’: 
    readerServer cfg = enter (readerToEither cfg) server 

Tôi là một người mới bắt đầu Haskell và tôi không quen thuộc với Wai nên không chắc chắn nơi để thậm chí bắt đầu. Tôi cần những thay đổi nào để tạo mã ví dụ trong bài đăng trên Blog để phân phối các tệp tĩnh?

Sửa: Vì nhận xét được ẩn từ giao diện mặc định, tôi đang dán chú thích cuối cùng của tôi ở đây:

Dưới đây là giảm bớt phiên bản của Matt code từ blog của mình. Tôi hợp nhất tất cả các mô-đun của mình thành một tệp duy nhất, xóa tất cả nội dung cơ sở dữ liệu nhưng không dọn sạch các tiện ích mở rộng/nhập. Khi tôi chạy mã này, tôi nhận được lỗi không khớp loại ở trên. Xin lưu ý rằng mã này không sử dụng Network.Wai.Middleware.Static và tôi đang sử dụng nhập đủ điều kiện của Servant StaticFiles.

Cảm ơn!

+1

Đối với người đầu tiên, tôi nghĩ rằng bạn cần phải thêm wai-app-static vào build-depends trong tệp .cabal của bạn. –

+0

Cảm ơn, Michael. Tôi thực sự tôi đã đặt gói trong tập tin cabal sai. Vì vậy, wai-middleware-static hoạt động tốt. Tôi đang chơi với các mã trong bài đăng blog liên kết và tôi nhận thấy nó chuỗi middlewares nên quyết định sử dụng middleware tĩnh. Có lẽ sẽ mất nhiều thời gian hơn để tìm hiểu cách sử dụng 'wai-app-static' trong ngữ cảnh đó. – Ecognium

+0

@Ecognium Bạn đã thấy [phần này] (https://haskell-servant.github.io/tutorial/server.html#serving-static-files) của hướng dẫn đầy tớ chưa? –

Trả lời

8

Như đã trình bày in the relevant section of servant's tutorial, toàn bộ thỏa thuận với enter là phải có xử lý yêu cầu của bạn sử dụng một số đơn nguyên m (trong trường hợp của bạn một số ReaderT đơn nguyên) và cung cấp một cách để chuyển đổi một tính toán trong m đến một tính toán trong tớ ' s tiêu chuẩn EitherT ServantErr IO đơn nguyên.

Vấn đề ở đây mặc dù là bạn xác định một loạt các yêu cầu xử lý trong ReaderT là một thêm để phục vụ các tập tin tĩnh, và gọi enter trên tất cả trong số này. Bộ xử lý ReaderT được chuyển đổi thành bộ xử lý EitherT ... chỉ tốt, nhưng enter cố gắng chuyển đổi cuộc gọi serveDirectory từ ReaderT ... thành EitherT .... Đây là khóa học sẽ không xảy ra bất cứ lúc nào sớm, vì serveDirectory không phải là một tính toán trong ReaderT ... để bắt đầu!

công chức có thể cho là chỉ để lại serveDirectory một mình - tại thời điểm này tôi không có ý kiến ​​nhất định về việc chúng tôi có nên làm điều đó hay không, hoặc tốt hơn là chỉ xử lý tệp được dán riêng , đến kết quả của việc gọi số enter trên tất cả các điểm cuối khác. Sau đây là cách này sẽ như thế nào (nhìn cho - NEW để xem các thay đổi):

type PersonAPI = 
    "users" :> Capture "name" String :> Get '[JSON] Person 
    -- NEW: removed Raw from here 

-- NEW 
type WholeAPI = PersonAPI :<|> Raw 

type AppM = ReaderT Config (EitherT ServantErr IO) 

userAPI :: Proxy PersonAPI 
userAPI = Proxy 

-- NEW 
wholeAPI :: Proxy WholeAPI 
wholeAPI = Proxy 

-- NEW: changed 'userAPI' to 'wholeAPI' 
app :: Config -> Application 
app cfg = serve wholeAPI (readerServer cfg) 

readerServer :: Config -> Server WholeAPI 
readerServer cfg = enter (readerToEither cfg) server 
       :<|> S.serveDirectory "/static" -- NEW 

readerToEither :: Config -> AppM :~> EitherT ServantErr IO 
readerToEither cfg = Nat $ \x -> runReaderT x cfg 

server :: ServerT PersonAPI AppM 
server = singlePerson 

singlePerson :: String -> AppM Person 
singlePerson str = do 
    let person = Person { name = "Joe", email = "[email protected]" } 
    return person 

Tôi đã đưa chủ đề này đến sự chú ý của các nhà phát triển đầy tớ khác anyway, cảm ơn! Chúng tôi đã không thực sự nghĩ về sự tương tác giữa enterserveDirectory cho đến nay (tốt, tôi đã không).

+0

Cảm ơn rất nhiều vì điều này! – runeks

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