I first started using Elm's recommended codec-ing scheme. I found that if I needed to round-trip an entity to an API, I needed
4 representations of the same entity. One on the client and one on server is given. But then 1 encoder representation and 1 decoder representation... both of which spell out the same information in the type alias. So in order to change the entity, I have 4 places that need maintenance.
No thanks.
Abusing ports, I arrived at a similar solution to what I explained previously in this thread for decoding. But since encoding is also monkey work, I wanted to abuse ports to launder that too. However, the process to do that was herky-jerky. A port/sub round trip for encoding, then an Elm HTTP call, then a port/sub round trip for decoding. Instead, I abandoned the Elm HTTP library altogether. I added in a fetch polyfill (
whatwg-fetch) and run the HTTP call in JS.
Notes
The JS fetch code could be generalized/improved even more, but this is all I need for calling my own APIs. Once tweaked and running for its intended use, it will rarely need to be touched.
Outgoing ports start with 'api' so that the startup code knows to wire them up. If Elm would let me, I would define only one outgoing port as `port apiRequest : Request a -> Cmd msg`, but that doesn't compile.
Overhead per API method is around 5 lines of code. One outgoing port, 2 incoming ports (1 success, 1 fail), and 2 for adding incoming ports to subscriptions list.
Most importantly, if my messages change, I only have 2 places to update them: client model and server model. No encoder/decoder maintenance.
Using strings to represent incoming ports is not ideal, but shouldn't need that much maintenance and are private.
Just starting to explore this, so maybe there is some blocking situation I haven't discovered yet.