Json and local storage with elm
In the quest of porting a react/redux-app named remorse to elm, once more I came across the requirement to store the current progress of the user to local storage. Now, dealing with json was easily the least enjoyable part of the port. elm requires you to specify encoders and decoders in order to get from json to your elm code and back. To me, it does seem repetitive. After all, e.g. in .NET, when I have some instance, reflection allows me to understand the instance and then lets me build a fast encoder / decoder at runtime. This option isn’t available in elm.
The one advantage this approach does have is forcing you to think very carefully about what you will put out to json. Your json models will most certainly become independent of your programming models, which is actually a good thing. Still …
Let us start with the user interaction. The user clicks on “Save current settings”…
The message is handled in the update function by creating a Command which will do the job. Let us look at the contents of the command.
The map
function is a straightforward mapper that extracts just those values that I care about in terms of persisting. That value is passed through an encoder, whose output is then stored.
Here’s the encoder
You see, we have to encode all that what we know about the target model into the encoder as well. To an old-fashioned Newtonsoft user this seemed ludicrous, but yes, reflection isn’t really a thing in functional programming, and looking at Haskell, one of the fathers of elm, to pull off something more comfortable than this, it requires the programmer to use certain metaprogramming directives to instruct the compiler to do certain work for us.
The final piece in the Puzzle is the storeObject
, which is an interop function, because elm doesn’t have an in-built API to talk to local storage.
The end result being that the desired values are stored in the browser’s local storage for later retrieval.
There is no explicit functionality to load the currently stored settings - this happens when the application starts up. How?
- The elm application is started, inside the init it is requested to load json from local storage
- Once loaded, the data is made available, decoded and sent into the
update
part of the application. - If data is available and correctly loaded, the data is taken into the main application model.
Let’s go in reverse this time, beginning with the retrieval functionality implemented in javascript.
Elm is very strict with regard to values entering your application from the outside. Basically, you perform a request (Command) and then wait for a response (Subscription):
Let us look at the subscription.
Using the decoder modelDecoder
, it is attempted to retrieve the data from local storage. The decoder
may fail, which should usually mean that a value has never been stored. Once the decoded model instance is available, it is piped into the system through a message (OnAppStateLoaded
).
Finally, the whole chain is triggered with the loadAppStateCommand
inside the init function which is called right at the beginning
of the program.
with loadAppState
being…
With the end result being, that when the application starts, settings will be loaded from local storage right into the model if there are settings available.