ArangoDB and Elm — authentication
Part 2: Authenticate from Elm
In part 1 of this series, we discussed setting up Arango, filling a collection with assemblies and placing them in a graph. In this part, I will show how to login to Arango from an Elm app.
First, let's set up the Elm app. I like the Elm-Material Design package very much, so that's the first thing I include in the package file.
Arango supports a few authentication options. For our case, JWT authentication is a good option. Fortunately, there's a good package for that. Adding some standard stuff, we end up with this elm-package.json:
"summary": "Client for Arango",
"debois/elm-mdl": "8.1.0 <= v < 9.0.0",
"NoRedInk/elm-decode-pipeline": "3.0.0 <= v < 4.0.0",
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0",
"elm-lang/http": "1.0.0 <= v < 2.0.0",
"simonh1000/elm-jwt": "5.0.0 <= v < 6.0.0"
"elm-version": "0.18.0 <= v < 0.19.0"
This is all boiler-plate to create a home for our Bim.elm code. You can find the code on github, but I'll walk you through, step by step.
If you clone the repo to your local machine, you should be able to get a login page when running
which is a script that runs elm-live with the right options.
If you look at the code, it looks all nice and clean, but it took me a lot of time and some cursing to get it exactly right. The JSON decoding is an especially tough subject.
The main module Bim.elm contains the startup and update functions, and the initial model. For people not used to Elm, having separate update functions for everything, even simple things like username and password, seems a bit tedious, but that's the spirit of Elm: it's explicit, and all updates are in one place.
The view and update functions related to logging in:
The Textfields have the option to link events, like
onInput, to Elm messages. The contents of the field are automatically passed with the message.
These messages go into the render loop, and are handled by the update function. That's how text that you type in input boxes, ends up in the app's Model, i.e. the state. The things like "Card" and "Textfield" are part of the elm-mdl library, and are basically wrappers for functions that eventually create html tags.
When the user clicks the button, the update function calls the "authenticate" function, that is defined in the Auth.elm file:
I'm passing in the complete model here. I could probably refactor this to only pass in the things that are needed in this context, but that's a matter of taste.
These are the kind of things that took me a long time. I had to fiddle with encoders and decoders a lot, before the compiler finally accepted it, and I got the right data in and out.
As I explain it to myself: at some point, Http.send is called. This function takes a Message ("Authenticated" in this case) that will encapsulate the Result of the http request. It also takes a Request thingy. The Jwt.authenticate function can create this request for me, if I give it Arango's authentication url, a decoder for the response, and an encoded Value, containing the credentials. Arango wants my username and password in the body of a POST request, so that's why I have to encode this in my "credentials" function.
The decoder that I give to Jwt.authenticate will translate the response into an Elm String, extracting the "jwt" field from the JSON that Arango returns.
The pipe operator |> behaves similar to the Elixir version; the thing to the left is added as the last argument to the function on the right.
The end result of calling the authenticate function is, that the main update function gets a message with a JWT. That's what we need to make some real requests to Arango, to get some data out of it. This will be the subject of the next part.