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 [email protected].
For more options, visit https://groups.google.com/d/optout.