FCCSpeedRun #2: Diving into Elixir
After building the Request Header Parser Microservice, (read about it here) I started to build the Timestamp Microservice.
For those who are new to FCC, here is a quick recap of the objective of the Timestamp Microservice.
Recap
Users can send timestamp in natural language format or in unix format, like so -
https://elixir-time-stamp.herokuapp.com/December%2015,%202015
https://elixir-time-stamp.herokuapp.com/1450137600
The expected output is a JSON string with unix and natural language timestamps like so -
{ "unix": 1450137600, "natural": "December 15, 2015" }
First Challenge
The first challenge was to find an Elixir Library which could parse the date.
I looked at many date/time parsing libraries including Timex, but I was unable to find a library which suited my use case, i.e. parse date in natural language format.
In Javascript, this would be as simple as this —
new Date("December 15, 2015")
Then a helpful camper, pointed me to this link of old Timex’s documentation. Particularly this line —
DateFormat.parse("Tue, 05 Mar 2013 23:25:19 GMT", "{RFC1123}")
Now as I mentioned earlier, I had come across Timex, but had not seen an example of Timex parsing natural language date so I thought Timex doesn’t parse natural language date.
But with this new piece of info, I started trying again.
Initial Attempt
The first thing I tried to do was to run the code above on the Elixir’s interactive terminal.
iex(1)> DateFormat.parse("Tue, 05 Mar 2013 23:25:19 GMT","{RFC1123}")** (UndefinedFunctionError) function DateFormat.parse/2 is undefined (module DateFormat is not available)
But as you can see this does not work in the terminal. I figured maybe the parsing function changed, the documentation from where I had picked up the code was pretty old after all. So I went back to Timex’s latest docs. This time I knew what I was looking for. I quickly found the parse
function. See here.
So I modified my above code and ran this.
iex(1)> Timex.parse("Tue, 05 Mar 2013 23:25:19 GMT", "{RFC1123}")
{:ok, #<DateTime(2013-03-05T23:25:19+00:00 GMT)>}
It worked.
My next step was to attempt parsing dates like these December 15, 2015
.
So I ran this,
iex(2)> Timex.parse("December 15, 2015")
** (UndefinedFunctionError) function Timex.parse/1 is undefined or private. Did you mean one of:* parse/2
* parse/3(timex) Timex.parse("December 15, 2015")
Hmm. What went wrong here? It was obvious from the error that parse expected at least two arguments.
So I just had to pass in the date string format, like I did earlier. (RFC1123)
For that I needed to find out the date format of natural language dates. How could I find that out? Mozilla docs came to the rescue and I found this line.
Given a string representing a time, parse() returns the time value. It accepts the RFC2822 / IETF date syntax (RFC2822 Section 3.3), e.g. "Mon, 25 Dec 1995 13:30:00 GMT".
Excited at having found the answer, I fired up my elixir terminal and ran this code.
iex(1)> Timex.parse("Mon, 25 Dec 1995 13:30:00 GMT", "{RFC2822}"){:error, "Expected at least one parser to succeed at line 1, column 0."}
As you can see, this did not work. I felt like I had tried everything but still could not do even a simple thing like parsing a date. I was about to give up.
Community to the rescue
Before I totally gave up, as a last attempt I thought of asking the Elixir community. I found the elixir slack channel and asked for help.
Pretty soon the good people from the community responded.
Benjamin Milde informed me that Timex does not support {RFC2822}. But he also pointed me to some relevant docs.
I could use a custom format with Timex. Yay!!
I little trial and error later, I came up with this code.
iex(2)> Timex.parse("December 15, 2015", "{Mfull} {0D}, {YYYY}")
{:ok, ~N[2015-12-15 00:00:00]}
Hurray! The date got parsed finally.
Writing Idiomatic Elixir
I finished this app and pushed to heroku. (Here’s how you can deploy Elixir code to Heroku) I asked fellow chingus at the FCC Cohorts for feedback and soon enough I got the feedback from Jay Ullman.
Dates in this format January 1, 2015
got parsed but not in this format January 1 2015
.
To fix that, initially I used a naive if-else solution, but it didn’t look pretty to me I so updated the code to use try/catch like this.
But even this solution didn’t look good enough to me. It worked, yes, but looked kinda dirty. What if I had to add more date formats later. Elixir does not support multiple catch clauses.
Again I turned to the community and I found my answer. This time Michał Muskała helped. Here is the updated code.
This is much better because not only is it idiomatic, I can add more date formats later if need be.
Finally, I pushed this code to heroku which fixed the previous error.
You can see the live version here.
Conclusion
The official Elixir and Phoenix docs are excellent but third party library docs may not be as good as they can be. But hey, Elixir is a young community and where it lacks, it more than makes up for it by offering such a helpful and passionate community as I have already demonstrated above.
So, I would certainly encourage people to try out Elixir.
It could be the next big thing in web development.
Have fun writing Elixir code. :)