A Post on a Good Post
Below I describe a functional way to persist data from the client to the database using Elm and F#, specifically
- Elm’s RemoteData.Http
- F#’s List.forAll
Elm’s core Http library lacks the feature to notify users when data they submit is being sent. As a result wonktonk users would click the submit button multiple times resulting in duplicated posts. What I wanted was a mechanism to notify the user when their post was in the process of being submitted. RemoteData.Http library by @ohanhi enables that functionality. RemoteData.Http builds open the RemoteData library allowing post request data in addition to get request data to be represented by the WebData type.
type alias WebData a =
RemoteData Http.Error a
type RemoteData e a
| Failure e
| Success a
With the WebData type I can display a spinner informing the user that the request is sent and preventing multiple submissions.
One of the challenges of using WebData for post requests is where to store the local data. It felt awkward to store both a property for the data and the post result. After assistance from Kris Jenkins and @zwilias I decided to represent the type as a tuple
problemForm : ( WebData data, data)
This design also aids testing because when the post is successful then both the data and result should be reset simultaneously. Grouping the two fields is more cohesive than two independent properties on a record.
isErrorResult resultProblemSolutionModel =
resultProblemSolutionModel.problemForm== ( RemoteData.NotAsked, problemFormInit )
The backend processes the post request by firing of async calls to the CosmosDB database. Results of the async upserts are collected in a results array value. I had some trouble understanding what exactly I should do with the results. Using F#’s applicative didn’t seems applicable, I wasn’t constructing a type from functions that returned wrapped types. I ended up verifying that all results were Ok if not I would return an error.
match List.forall (fun elem -> match elem with | Ok _ -> true | Error _ -> false) (Seq.toList results) with
| true ->
return new HttpResponseMessage(HttpStatusCode.Created, Content = stringContent)
| false ->
return new HttpResponseMessage(HttpStatusCode.InternalServerError)
I am open to suggestions on improvements.
P.S. if you are a policy wonk, broadly defined (informed citizen, student, advocate, practitioner and professional who likes to apply logic and facts to public issues) please consider joining out beta. It would be much appreciated and help an Elm startup start!