On Wednesday, January 18, 2017 at 7:03:37 AM UTC, Max Goldstein wrote:
>
> I came upon the idea that the client (that's you) will provide a type 
> alias for each resource's attributes (and perhaps other crucial 
> information), and I could generate code that would retrieve resources of 
> those types. Generating code also allows the tool to create JSON encoders 
> and decoders, a common pain point.
>

I've been doing something very similar and it is proving very worthwhile, 
so I would encourage you to pursue this. In my case, I have a data model 
and a mapping of that onto a set of REST endpoints. The model that 
describes this is implemented Java and I use a (horrible) templating 
library called StringTemplate to do codegen from it.

For Elm, I output one (big) file called Model.elm, that gives me the data 
model mapped onto Elm, and encoders and decoders for it. Then for each 
grouping of endpoints (each service implemented in Java provides the 
grouping) I generate one Elm file that implements the Http logic for the 
service. I haven't open sourced this, but it might not be of much use to 
you anyway.

Each service requires a set of callback functions to be passed in - one for 
each endpoint, plus one for each endpoint when it results in an error, plus 
a default error handler for cases when the endpoint specific error handler 
doesn't process the error. The service also defines a set of convenience 
functions for triggering a call to the service. You nest the services 
update function inside yours and pass it the callbacks. Putting all the 
callback functions together in a record is a design choice I might re-think 
for something less monolithic. Anyway, here is an example of using it.

cseCallbacks : CSE.Callbacks Model Msg
cseCallbacks =
    let
        default =
            CSE.callbacks -- Default no-op callbacks so you only specify 
what you need.
    in
        { default
            | retrieveWithContainerBySlug = retrieveWithContainerBySlug
            , error = error
        }

update : Msg -> Model -> ( Model, Cmd Msg )
update action model =
    case (Debug.log "Client.State" action) of
        CSEApi action_ ->
            CSE.update cseCallbacks action_ model  -- Nesting the services 
update function.

        SelectLocation location ->
            ( model, CSE.invokeRetrieveWithContainerBySlug CSEApi location 
) -- Invoking a service helper function.

Another possibility would be to use an API description meta-data such as 
Swagger. A Swagger codegen for Elm could easily output something useable.

Its definitely worth doing - the current project I am working on I have 
about 6K lines of Elm generated, all at practically zero effort (well, 
except the days and days I spent setting up the code generator, but that is 
effort I can re-use over and again). Project before that was about 4K 
lines. These were not huge APIs, maybe 4 or 5 entity types.

I am planning to move my codegen templates over from StringTemplate to Elm 
at some point. Now that I have server side rendering with Elm working. I 
defined a static Program type like this for it:

type alias StringProgram =
    Program Value String Never

https://github.com/rupertlssmith/elm-server-side-renderer/blob/master/src/ServerSide/Static.elm#L24

I think Elm will be well suited to writing code generators - in a manner 
similar to how it 'codegens' Html. You can design a set of functions for 
constructing the component parts of the output language you are working 
with. Elm is good for doing complex AST manipulation and it can be set up 
to guarantee correctly formed output. Code generation of Elm in Elm will be 
a mind bender.

-- 
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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to