{-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE OverloadedStrings #-} import Control.Concurrent import Control.Monad import Control.Monad.IO.Class import Data.Text.Encoding (encodeUtf8) import Network (withSocketsDo) import Network.HTTP.Client hiding (Proxy) import Network.HTTP.Client.MultipartFormData import Network.Wai import Network.Wai.Handler.Warp import Servant import Servant.Multipart -- Our API, which consists in a single POST endpoint at / -- that takes a multipart/form-data request body and -- pretty-prints the data it got to stdout before returning 0. type API = MultipartForm MultipartData :> Post '[JSON] Integer api :: Proxy API api = Proxy -- The handler for our single endpoint. -- Its concrete type is: -- MultipartData -> Handler Integer -- -- MultipartData consists in textual inputs, -- accessible through its "inputs" field, as well -- as files, accessible through its "files" field. upload :: Server API upload multipartData = do liftIO $ do putStrLn "Inputs:" forM_ (inputs multipartData) $ \input -> putStrLn $ " " ++ show (iName input) ++ " -> " ++ show (iValue input) forM_ (files multipartData) $ \file -> do content <- readFile (fdFilePath file) putStrLn $ "Content of " ++ show (fdFileName file) ++ " at " ++ fdFilePath file putStrLn content return 0 startServer :: IO () startServer = run 8080 (serve api upload) main :: IO () main = withSocketsDo $ do forkIO startServer -- we fork the server in a separate thread and send a test -- request to it from the main thread. manager <- newManager defaultManagerSettings req <- parseRequest "http://localhost:8080/" resp <- flip httpLbs manager =<< formDataBody form req print resp where form = [ partBS "title" "World" , partBS "text" $ encodeUtf8 "Hello" , partFileSource "file" "./servant-multipart.cabal" , partFileSource "otherfile" "./Setup.hs" ]