Recipe: Multipart file upload

Goal: Accept a file from a browser form.

Forms must use enctype="multipart/form-data" or request.files stays empty.

open System.IO
open Suave
open Suave.Filters
open Suave.Operators
open Suave.Successful
open Suave.RequestErrors

let handleUpload =
  request (fun r ->
    let files = r.files
    if files.Count = 0 then
      BAD_REQUEST "No file"
    else
      let file = files.[0]
      let dest = Path.Combine("uploads", file.fileName)
      Directory.CreateDirectory("uploads") |> ignore
      File.Copy(file.tempFilePath, dest, true)
      OK (sprintf "Saved %s" file.fileName))

let app = choose [
  GET >=> path "/" >=> OK """
    <form action="/upload" method="POST" enctype="multipart/form-data">
      <input type="file" name="file" />
      <button type="submit">Upload</button>
    </form>"""
  POST >=> path "/upload" >=> handleUpload
]

startWebServer defaultConfig app

More: File handling.