# Encoding user created content in a URL

**URL:** https://discourse.elm-lang.org/t/encoding-user-created-content-in-a-url/8914
**Category:** Show and Tell
**Created:** [January 30, 2023, 1:11am UTC](https://discourse.elm-lang.org/t/encoding-user-created-content-in-a-url/8914 "2023-01-30T01:11:57Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![ChrisWellsWood](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/chriswellswood/32/5293_2.png) [@ChrisWellsWood](https://discourse.elm-lang.org/u/ChrisWellsWood)
#### Post date: [January 30, 2023, 1:11am UTC](https://discourse.elm-lang.org/t/encoding-user-created-content-in-a-url/8914/1 "2023-01-30T01:11:57Z")

</div>

I’ve just updated my MIDI Surf app that I posted about a few weeks ago, adding a feature where users can share the MIDI controllers that they make. Just to give everyone the background, MIDI Surf is a highly customisable web-based MIDI controller, which you can use to control a range of musical devices like synthesisers, samplers, lighting rigs etc.

With the initial release, there was no (easy) way to save the controllers that you made, which is a pain, as it can be quite a labourious process to make a controller in the first place, given that you need to dig through the device manual to figure out what you can control and how you control it. I wanted users to be able to share via a URL, and while I could do this with a server, I wanted to keep the whole thing as simple as possible, so I tried encoding the controller into the URL. I know this isn’t a new idea, but I’m really pleased with how seamlessly it worked!

The bulk of the controller data is contained in a recursive data type called `Controller`, which looks like this:

```elm
type Controller
    = Module String Controller
    | Row (List Controller)
    | Column (List Controller)
    | Note NoteState
    | Chord ChordState
    | CCValue CCValueState
    | Command CommandState
    | Sequence SequenceState
    | Fader FaderState
    | XYFader XYFaderState
    | PitchBend PitchBendState
    | MidiLog
    | Space

```

So to create something like this:

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/1/1a113665b412f5358f3bcdb8d3b31bed95fa31a2.png)

It is built up from a `Column` containing multiple `Row`s with various different buttons that send note information or change parameters on the synth.

The state of your controllers was already saved to local storage using a port, encoding the value using the excellent `miniBill/codec` library, which makes the recursive data type a breeze to work with. When adding the save feature, I built on this by enabling users to export this as string to a file and then importing it back in. To make the URL feature, I initially tried to make a really terse encoding by hand with a corresponding parser, but I remember reading that JSON compresses really well with GZIP, so thought that maybe I could just encode the string, convert it to bytes, compress it and then base 64 encode it, then chuck in a url as a query string. I’m using `elm/bytes`, `folkertdev/elm-flate`, `danfishgold/base64-bytes`:

```elm
encodedPage =
    Codec.encodeToString 0 pageCodec page

 compressedPage =
    encodedPage
        |> Encode.string
        |> Encode.encode
        |> Flate.deflateGZip
        |> Base64.fromBytes

```

For a relatively simple controller, I get around 4x compression, but on the most complex one I’ve tested, I get over 12x (15633 chars to 1248). It’s pretty much instantaneous on all the devices I’ve tested too. [This link](https://midisurf.app/?page=H4sIAAAAAAAA%2F%2B1Zy26bQBT9FTprL2Ib3JZlk7abOIqSVk0UZTGGiRl1DBEMbVPL%2F94DDo86RGIIji9SJC%2B4l8vcc84M18fymnlReCeXzF0zXyxSXNxxlYgRW%2FL7S%2FlXMHeyGWVFOo6UEnFWqDnK2EX0m40Yj5cJc29uiuw88lMlqhvsWyATq3reQiRCL%2FKFb8lQR5YOhPX94vQdGxVLHEcqXYXVEuXazR3PIl3rt2a%2FhIo8qR%2BYOz46GrF7qb2AubMxWAQ8DIWqKBwHTvXkbc5TRWmN4wmPf36NxcP%2FVYovhNqKUxRerrhSDVW4hWyiuU6RD1OlNrhXPNUS%2BgTAjKGfymWgD499CmTG2GnIbgOYMXQisjtANlTsMyAzxr6fI3OL28WDL5k%2BDiFOJaGW0N8DmDF0GkfJ%2BQBkxthpyP4RwIyh05B9hktz7J9UWls7q8gBvSJsQhaht8FDiFNJqCX0Adsep5PtIYK9k%2B%2BhcWQGbHsoWYS%2Bpo9NiFNJqCX0Adseu5PtOfj3r93J8pA4LQ4uzaHTOC2ULEJvg6cTJxr7YXfyPfvZD1PoA7Y99nBtjz1g20PJIvQ1faadOB38%2B3fayfLsZytMoXdyPDTegOlwbY%2BNS3PoNGQnZREwebJPxcHwP7Av3Mdfc2UenDmmyZz%2FAecJXuttKEPmQoA8OBexJ0IN%2B4eM552lqwVWcJtFGVdLA%2BMTUVpNrrnwZbpqKMO986zBjiSlFIflhr0WtX3ISnLUBuQmyNMk9%2FKNmyJPk1sPG2cjv0MOb2nJr%2FlVvLp%2BlvcEVOrEEYNnHj0yR6ZOHWH1YwBB0eMJ%2BXwNdBjvdECM5fLosQMy9Q4IK3URPNthV94fgaxP2awk1629vFfXWYsdfUtx32RsLWPDfMEx3X6qus9qZZ3IxEP7RLDNPyoCh3%2F5IQAA) should open MIDI Surf and ask you if you want to import a controller called “Elm Discourse”.

Anyway, I thought people might be interested. Here’s the source if you fancy a gander: [GitHub - mochreach/midi-surf: A flexible and powerful MIDI controller in your browser!](https://github.com/mochreach/midi-surf/). Thanks to @miniBill, @folkertdev, danfishgold and @evancz for the libraries that make this work.

---

<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: [February 9, 2023, 1:12am UTC](https://discourse.elm-lang.org/t/encoding-user-created-content-in-a-url/8914/2 "2023-02-09T01:12:15Z")

</div>

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