With Fable.Remoting, it is really simple to upload and download files and other binary content and it goes like this:

• Use byte[] as input of a remoting function for upload Upload : byte[] -> Async<unit>
• Use Async<byte[]> as output of a remoting function to download Download : string -> Async<byte[]>

When using byte[] as input or output, the data transport is automatically optimized for binary content and will bypass the JSON serialization phase entirely.

However, that is of course not the full story, because first of all, how do you get a byte[] from a file coming through the browser for upload. For downloading, once you get byte[] from the backend, how do you save it as a file on the user system?

### From File to byte[]

When you use an <input type="file" /> from the browser, you can obtain a File instance of the selected file which you can upload to the backend. The Fable.Remoting.Client package includes an extension function called ReadAsByteArray() which does what it says: converts the file into raw byte[] that can be used as input for uploading:

open Fable.Remoting.Client
open Browser.Types

let upload (file: File) = async {
return output
}


When you receive byte[] from the backend (for a download), you can call the SaveFileAs(fileName: string) : unit extension function on the binary data to save it as a file on the users system:

open Fable.Remoting.Client

}


The SaveFileAs funcion detects the mime-type/content-type automatically based on the file extension of the file input. Alternatively, you can provide your own content type if you wish as follows:

let download (fileName: string) = async {
}


### Data URLs From byte[]

Fable.Remoting.Client includes another extension function for byte[] which converts it to a Data URI as follows. This is useful for example if you are returning images from the backend and you want to show them easily:

open Fable.Remoting.Client

// data
let imageData : byte[] = ...
let dataUrl = imageData.AsDataUrl()

// view
Html.img [ prop.src dataUrl ]