Help in creating a Upload API in Servant

I’m trying to implement this POST request
curl -F "file=@test.txt" https://api.anonfiles.com/upload
in Servant but kind a lost can anybody help ?

1 Like

The first step would be to define your API as a type!

Then implement a server implementation for the API (the type you defined for it)

Then serve that server implementation using Warp’s run

Where are you stuck?

1 Like

Hi,

here is a small program that should help you get started:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}

module Main where

import Control.Monad (forM_)
import Control.Monad.IO.Class (MonadIO (liftIO))
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Text as Text
import qualified Network.Wai.Handler.Warp as Warp
import Servant (JSON, Post, Proxy (..), Server, type (:>))
import qualified Servant
import Servant.Multipart
  ( Mem,
    MultipartData,
    MultipartForm,
  )
import qualified Servant.Multipart as SMP

main :: IO ()
main = do
  putStrLn "Servant-Upload - try uploading to http://localhost:8080/upload - you should find the file in ./upload"
  startServer

type API = "upload" :> MultipartForm Mem (MultipartData Mem) :> Post '[JSON] Integer

startServer :: IO ()
startServer = Warp.run 8080 (Servant.serve (Proxy :: Proxy API) upload)

upload :: Server API
upload multipartData = liftIO $ do
  forM_ (SMP.files multipartData) $ \file -> do
    let content = SMP.fdPayload file
    LBS.writeFile ("./upload/" ++ Text.unpack (SMP.fdFileName file)) content
    putStrLn $ "received file " ++ Text.unpack (SMP.fdFileName file)
  return 0

in order to compile this you need some dependencies - you should add this to the dependency-section of your .cabal file:

    build-depends:    base ^>=4.16.0.0,
                      bytestring ^>= 0.11,
                      servant ^>= 0.19,
                      servant-multipart ^>= 0.12,
                      servant-server ^>= 0.19,
                      text ^>= 1.2,
                      warp ^>= 3.3

(versions should be ok for now but might vary - if in doubt look at the documentation of those libraries)

Before starting this (for example with cabal run) you should create a upload-folder (for example mkdir upload) as the program will put the uploaded files there and will panic if the path ./upload/[uploadedfilename] is not valid :wink: )

Then something like curl -F "file=@CHANGELOG.md" http://localhost:8080/upload should upload the file and you should see it in the upload folder together with a message saying so.


For more details there is a servant cookbook entry on File Upload here and you should find plenty of information in the servant docs in general.

Of course feel free to ask for more details.

Have fun.

2 Likes