On Friday, September 23, 2016 at 12:45:31 PM UTC+1, Rupert Smith wrote:
>
> I am wondering if all of this can be wrapped up in a more convenient 
> interface that the consumer of a REST service can make use of in a simpler 
> manner.
>

I now have this working and here is how it works.

Firstly, I define a set of call-back functions which will be notified when 
REST operations complete:

callbacks : Account.Service.Callbacks Model Msg
callbacks =
    { findAll = accountList
    , findByExample = accountList
    , create = \account -> \model -> ( model, Cmd.none )
    , retrieve = \account -> \model -> ( model, Cmd.none )
    , update = \account -> \model -> ( model, Cmd.none )
    , delete = \response -> \model -> ( model, Cmd.none )
    , error = error
    }

The return type lets me update the model and issue follow on commands, just 
like update. In fact these callbacks will be invoked from within the update 
function of the REST module.

In the update function of the module that wants to use it, I need a Msg for 
events that are handed down to the REST module:

update' : Msg -> Model -> ( Model, Cmd Msg )
update' action model =
    case action of
        ...
        AccountApi action' ->
            Account.Service.update callbacks action' model

And then to invoke a REST endpoint I have set up convenience functions to 
make the calls and Cmd.map the outcomes as events local to this module 
(which are then handed back down to the REST module):

        Init ->
            ( { model | selected = Set.empty }, 
Account.Service.invokeFindAll AccountApi )

I pass all errors back to just one error handler, not one per endpoint. 
This may prove to be a limitation in the future, but seems ok for now. 
Mostly I am interested in handling 401 with a logout, 404 with a not found 
page, and anything else with a "whoops something went wrong" generic error 
message. Have not done the 404 yet, but the error handling function can be 
typed generically enough to work with any model or message type in the 
generic case:

error : Http.Error -> model -> ( model, Cmd msg )
error httpError model =
    case httpError of
        Http.BadResponse 401 message ->
            ( model, Auth.logout )

        _ ->
            ( model, Cmd.none )

The use of callbacks simplifies the update function in the module using the 
REST module, as there is no need to define Msgs for every event resulting 
from the Http calls. I think the type of the Callbacks is very useful in 
guiding the caller as to what exactly they need to implement, whereas 
leaving it up to the caller to figure out what events they need to handle 
is much less helpful.

It does mean that the flow of control goes from the calling module to the 
REST module, back to the calling module, back to the REST module, so I have 
more code in total than I might otherwise need. On the other hand, I have 
now managed to code gen the full REST interface with its model, 
encoders/decoders and convenience fuctions to make the REST calls - so my 
priority was removing as much boiler plate as possible from the calling 
module.

The amount of boiler plate around json and REST compared with what you need 
in javascript does seem to be a weakness of Elm. In my adventures so far, 
if I had to pick an area for improvement that would help to make Elm a more 
popular language I think it would be this.

I am now able to talk json over REST to my services without having to hand 
code all this boiler plate, which feels really good. Now I can get on with 
the fun part of making a nice UI.

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to