Skip to content

Serve a file from the back-end

In SAFE apps, you can send a file from the server to the client as well as you can send any other type of data.

1. Define the route

Since the standard template uses Fable.Remoting, we need to edit our API definition first. Find your API type definition in Shared.fs. It's usually the last block of code. The one you see here is named ITodoAPI. Edit this definition to have the download member you see below.

type ITodoAPI =
    { //...other routes 
      download : unit -> Async<byte[]> }

2. Add the route

Open the Server.fs file and find the API that implements the definition we've just edited. It should now have an error since we're not matching the definition at the moment. Add the following route to it

//...other functions in todosApi
download =
    fun () -> async {
        let byteArray = System.IO.File.ReadAllBytes("file.txt")
        return byteArray
    }

Make sure to replace "file.txt" with your file that is placed in src/Server or relative path

3. Using the download function

Since the download function is asynchronous, we can't just call it anywhere in our view. The way we're going to deal with this is to create a Msg case and handle it in our update funciton.

a. Add a couple of new cases to the Msg type
type Msg =
    //...other cases
    | DownloadFile
    | FileDownloaded of byte[]
b. Handle these cases in the update function
let update (msg: Msg) (model: Model): Model * Cmd<Msg> =
        match msg with
    //...other cases
    | DownloadFile -> model, Cmd.OfAsync.perform todosApi.download () FileDownloaded
    | FileDownloaded file ->
        file.SaveFileAs("downloaded-file.txt")
        model, Cmd.none // You can do something else here

The SaveFileAs function detects the mime-type/content-type automatically based on the file extension of the file input

c. Dispatch this message using a UI element
Html.button [
    prop.onClick (fun _ -> dispatch DownloadFile)
    prop.text "Click to download" 
]

Having added this last snippet of code into the view function, you will be able to download the file by clicking the button that will now be displayed in your UI. For more information visit the Fable.Remoting documentation