# Sending a File through a port

**URL:** <https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440>\
**Category:** Learn\
**Created:** [April 5, 2019, 1:49pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440 "2019-04-05T13:49:23Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dan\_Abrams](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dan_abrams/32/3171_2.png) [@Dan\_Abrams](https://discourse.elm-lang.org/u/Dan_Abrams)\
**Post date:** [April 5, 2019, 1:49pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/1 "2019-04-05T13:49:23Z")

</div>

I’m working on a work project where a user can select a PDF using `elm/file` and then send it to our server. Given other dependencies, we’re still using `elm/http 1.0`, which doesn’t support file uploads.

My solution was to convert to a dataUri and send across a port to upload, but this isn’t ideal. On large files this can be problematic on some browsers, either locking up or simply failing.

I have another project coming up where I’ll have to send files across a port to be store as blobs in an indexedDB, so I’m looking for guidance:

**Is there a better way?**

**If not, what’s the path forward? Add file encoding to `elm/json`?**

---

<div class="post-metadata">

**Author:** ![Herteby](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/herteby/32/1329_2.png) [@Herteby](https://discourse.elm-lang.org/u/Herteby)\
**Post date:** [April 5, 2019, 2:06pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/2 "2019-04-05T14:06:08Z")

</div>

Hmm, one weird hack I can think of would be to send the file using `Http.fileBody`, and then intercept it with a service worker 😄 Probably not the best though.

Doh nvm, you said you’re using http 1.0. I somehow thought you wanted to get the file into JS.

edit2: or actually I guess I read it correctly after all…

---

<div class="post-metadata">

**Author:** ![Dan\_Abrams](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dan_abrams/32/3171_2.png) [@Dan\_Abrams](https://discourse.elm-lang.org/u/Dan_Abrams)\
**Post date:** [April 5, 2019, 2:10pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/3 "2019-04-05T14:10:04Z")

</div>

> [@Herteby](#):
>
> Hmm, one weird hack I can think of would be to send the file using `Http.fileBody` , and then intercept it with a service worker 😄 Probably not the best though.

I considered that for the upcoming project, but have to support some iOS devices that predate service workers (which are only about a year old on iOS).

---

<div class="post-metadata">

**Author:** ![hpate](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/hpate/32/2094_2.png) [@hpate](https://discourse.elm-lang.org/u/hpate)\
**Post date:** [April 5, 2019, 2:25pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/4 "2019-04-05T14:25:34Z")

</div>

I haven’t tested this, but I was looking at how file inputs work and it basically keeps the `File` object from JS around.

One way you could work with that is using `createObjectURL` to get a `blob:` URL that you can use to reference the file later on. You could send the blob URL to Elm, and when it’s time to send it to the server send info out a port (including the `blob:` url), and have it do the upload from JS by reading the blob. We do something similar for this where we send the real `File` object and the Blob URL in from a custom element for file upload, and we use that blob URL as a `src` for image previews.

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [April 5, 2019, 2:35pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/5 "2019-04-05T14:35:31Z")

</div>

> [@Dan\_Abrams](#):
>
> Given other dependencies, we’re still using `elm/http 1.0` , which doesn’t support file uploads.

Can you list the dependencies? Maybe it would be easier to just upgrade everything.

---

<div class="post-metadata">

**Author:** ![Dan\_Abrams](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dan_abrams/32/3171_2.png) [@Dan\_Abrams](https://discourse.elm-lang.org/u/Dan_Abrams)\
**Post date:** [April 5, 2019, 3:00pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/6 "2019-04-05T15:00:06Z")

</div>

> [@hpate](#):
>
> One way you could work with that is using `createObjectURL` to get a `blob:` URL that you can use to reference the file later on. You could send the blob URL to Elm, and when it’s time to send it to the server send info out a port (including the `blob:` url), and have it do the upload from JS by reading the blob. We do something similar for this where we send the real `File` object and the Blob URL in from a custom element for file upload, and we use that blob URL as a `src` for image previews.

We’re going the other way through the port, and this is essentially what we’re doing. But as I said in the initial post, it’s unreliable with large files.

> [@pdamoc](#):
>
> Can you list the dependencies? Maybe it would be easier to just upgrade everything.

It’s `lukewestby/elm-http-builder`, but the team took a vote and voted against refactoring to remove (I had already started working on a replacement). Regardless, we have a project coming up where we have to send through a port to send a blob to an api that isn’t wrapped by a core library or exploration yet (indexedDB), and I’m sure there’s other instances where it will come up.

---

<div class="post-metadata">

**Author:** ![hpate](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/hpate/32/2094_2.png) [@hpate](https://discourse.elm-lang.org/u/hpate)\
**Post date:** [April 5, 2019, 3:13pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/7 "2019-04-05T15:13:55Z")

</div>

Using `createObjectURL` just gives you a string, it doesn’t base64 it or anything, it doesn’t have any overhead on the Elm side.

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [April 5, 2019, 3:23pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/8 "2019-04-05T15:23:34Z")

</div>

> [@Dan\_Abrams](#):
>
> Regardless, we have a project coming up where we have to send through a port to send a blob to an api that isn’t wrapped by a core library or exploration yet (indexedDB), and I’m sure there’s other instances where it will come up.

For these very custom cases I guess the best way to handle it is to delegate everything to JS.

Get the fileRef in Elm, send it to JS as a `Value` and then read the contents and send them where they need to get it in JS.

---

<div class="post-metadata">

**Author:** ![Dan\_Abrams](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dan_abrams/32/3171_2.png) [@Dan\_Abrams](https://discourse.elm-lang.org/u/Dan_Abrams)\
**Post date:** [April 5, 2019, 6:18pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/9 "2019-04-05T18:18:24Z")

</div>

> [@pdamoc](#):
>
> Get the fileRef in Elm, send it to JS as a `Value` and then read the contents and send them where they need to get it in JS.

Can we encode an opaque type as a value? How do we get the fileRef on the elm side?

I considered writing a clone of elm/file using ports to do the file selection, but it required attaching an invisible node to the DOM which is something I’m loathe to do.

---

<div class="post-metadata">

**Author:** ![jreusch](https://avatars.discourse-cdn.com/v4/letter/j/b5e925/32.png) [@jreusch](https://discourse.elm-lang.org/u/jreusch)\
**Post date:** [April 5, 2019, 6:25pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/10 "2019-04-05T18:25:36Z")

</div>

I built a file sharing app to tryout Elm _for real_ some months ago, which was in the pre-`elm/file` and `elm/html@1` days. What I ended up doing is sending custom `Request` records that mirrored the `elm/html` structure over a port. I left the javascript `File` object I got from the event unencoded (using `Json.Decode.value`) and sent the raw `Value` inside of the `Request` over a port, which worked. The Javascript code was basically a copy of the relevant Kernel code inside of `elm/html`, with the bonus feature of handling file uploads.

Here is my event decoder: [https://gitlab.com/arkandos/shareit/blob/master/src/FileHandle.elm#L84](https://gitlab.com/arkandos/shareit/blob/master/src/FileHandle.elm#L84)  
The Port and `Request` record, Elm side: [https://gitlab.com/arkandos/shareit/blob/master/src/Ports.elm](https://gitlab.com/arkandos/shareit/blob/master/src/Ports.elm)  
Javascript Callback: [https://gitlab.com/arkandos/shareit/blob/master/public/initialize.js#L23](https://gitlab.com/arkandos/shareit/blob/master/public/initialize.js#L23)

Please don’t blast the code too much, this was the first time I tried to do something “serious” in Elm. Hope it helps 🙂

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [April 5, 2019, 11:18pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/11 "2019-04-05T23:18:56Z")

</div>

> [@Dan\_Abrams](#):
>
> Can we encode an opaque type as a value? How do we get the fileRef on the elm side?

You use a custom event handler on an `input`. It would look [like this](https://ellie-app.com/5bnxKMFYzwka1). You can then use the FileRef to send the file where it needs to get using your preferred JS method. .

---

<div class="post-metadata">

**Author:** ![AleXoundOS](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/alexoundos/32/1481_2.png) [@AleXoundOS](https://discourse.elm-lang.org/u/AleXoundOS)\
**Post date:** [April 10, 2019, 8:39am UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/12 "2019-04-10T08:39:01Z")

</div>

Are there any benefits in using [https://github.com/phylor/elm-image-upload](https://github.com/phylor/elm-image-upload) versus this?

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [April 10, 2019, 10:30am UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/13 "2019-04-10T10:30:17Z")

</div>

> [@AleXoundOS](#):
>
> Are there any benefits in using [https://github.com/phylor/elm-image-upload](https://github.com/phylor/elm-image-upload) versus this?

No benefit comes to my mind but maybe there is something I’m missing.

There is a tradeoff involved. The approach you linked has a simpler decoder but it pays for this by making you deal with ids. The approach I linked solves the issue without ids at the expense of a more complex decoder.

Oh, and welcome to the Elm Discourse. May you find all the answers you seek. 😃

---

<div class="post-metadata">

**Author:** ![AleXoundOS](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/alexoundos/32/1481_2.png) [@AleXoundOS](https://discourse.elm-lang.org/u/AleXoundOS)\
**Post date:** [April 10, 2019, 6:43pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/14 "2019-04-10T18:43:23Z")

</div>

Thank you for welcoming 🙂  
Yeah, I’m quite a newbie. The thing I still don’t understand - is it possible to avoid base64 overhead when uploading arbitrary file/data to a server?

Some time ago I wrote [file uploading (to a server) app](https://github.com/AleXoundOS/elm-file-upload/blob/json-file-send/Main.elm#L130) based on the approach I linked which uses base64 and I guess it is a requirement there. Consequently, file contents are encapsulated in json. However, your example has no base64 by default and it’s not clear for me if it’s really suitable for uploading arbitrary files to a server.

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [April 10, 2019, 8:16pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/15 "2019-04-10T20:16:08Z")

</div>

> [@AleXoundOS](#):
>
> However, your example has no base64 by default and it’s not clear for me if it’s really suitable for uploading arbitrary files to a server.

The example above was for the constrain of `http 1.0`. If you have no such constrain, just use `http 2.0` and the new `File` module (it should be the most efficient approach).

Also, a key point of the ports approach was that you handle the file upload in JS, this means that you can read the file as binary and upload it as binary. You don’t have to go through the conversion.

---

<div class="post-metadata">

**Author:** ![AleXoundOS](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/alexoundos/32/1481_2.png) [@AleXoundOS](https://discourse.elm-lang.org/u/AleXoundOS)\
**Post date:** [April 11, 2019, 10:16am UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/16 "2019-04-11T10:16:42Z")

</div>

> [@pdamoc](#):
>
> The example above was for the constrain of `http 1.0` . If you have no such constrain, just use `http 2.0` and the new `File` module (it should be the most efficient approach).

Ah, my fault was that I wasn’t aware of the `elm/file` package and its purpose. It’s a relatively new package (appeared half a year ago). It looks like major progress over several custom solutions that were flying around the internet.

> [@pdamoc](#):
>
> Also, a key point of the ports approach was that you handle the file upload in JS, this means that you can read the file as binary and upload it as binary. You don’t have to go through the conversion.

And in contrast `elm/file` package uses I guess some implicit native code approach without exposing JS internals to the programmer, right?  
Maybe a bit offtopic, but I couldn’t find an explanation on how project sources like [`Elm/Kernel/File.js`](https://github.com/elm/file/blob/1.0.5/src/Elm/Kernel/File.js) get involved in the build? Is it the case when the package is trusted (couldn’t see any notion on this) and allowed to use native code?

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [April 11, 2019, 8:23pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/17 "2019-04-11T20:23:31Z")

</div>

> [@AleXoundOS](#):
>
> Is it the case when the package is trusted (couldn’t see any notion on this) and allowed to use native code?

With `0.19`, use of Kernel(JS) modules has been restricted to two organizations: `elm` and `elm-explorations`.

This kind of source code is not documented is because it is not really intended to be modified by contributors outside of the core team.

---

<div class="post-metadata">

**Author:** ![AleXoundOS](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/alexoundos/32/1481_2.png) [@AleXoundOS](https://discourse.elm-lang.org/u/AleXoundOS)\
**Post date:** [April 11, 2019, 10:22pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/18 "2019-04-11T22:22:35Z")

</div>

> [@pdamoc](#):
>
> With `0.19` , use of Kernel(JS) modules has been restricted to two organizations: `elm` and `elm-explorations` .
> 
> This kind of source code is not documented is because it is not really intended to be modified by contributors outside of the core team.

Thank you! I got it.

---

<div class="post-metadata">

**Author:** ![madasebrof](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/madasebrof/32/363_2.png) [@madasebrof](https://discourse.elm-lang.org/u/madasebrof)\
**Post date:** [April 18, 2019, 3:20pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/19 "2019-04-18T15:20:13Z")

</div>

Hey Dan, you may want to check out:

> **[simonh1000/file-reader](https://github.com/simonh1000/file-reader)**
>
> Elm 0.18 native bindings for HTML5 FileReader API. Contribute to simonh1000/file-reader development by creating an account on GitHub.

for inspiration. We use this in production.

Works like a charm (we use it to upload PDFs to our server, then we upload from there to S3) , but it’s native so 0.18 only. (One of the reason we haven’t move to 0.19…)

Best,

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [April 28, 2019, 3:20pm UTC](https://discourse.elm-lang.org/t/sending-a-file-through-a-port/3440/20 "2019-04-28T15:20:17Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
