Serverless iCal Parsing

Raymond Camden
Aug 24, 2017 · 4 min read

Today’s post isn’t necessarily too interesting code-wise, but it touches upon some greater, more broad, serverless topics that I’d like to bring up. A few weeks ago I discovered an interesting GitHub repository: https://github.com/gadael/icsdb.

This repository contains iCal files (think plain text calendar data) for non-working days for all 50 US states and various European countries. This could be useful in a number of ways, if, of course, you can parse the iCal data. I thought it might be interesting to build a simple service that would take a URL pointing to iCal data and return the information in JSON form.

There are multiple different ways of parsing iCal, but I felt ical.js by Mozilla was good enough. The ical.js library is pretty complex, letting you work with iCal data like a component, calling different methods to find data, but it can also just return a simple parsed version of the text. Here is the code I came up with:

const rp = require('request-promise');
const ical = require('ical.js');

function flattenEvent(e) {
let event = {};
for(let i=0;i<e[1].length;i++) {
let prop = e[1][i];
event[prop[0]] = prop[3];
//console.log('e',prop);
}
return event;
}

exports.main = (args) => {

return new Promise((resolve, reject) => {
rp(args.url).then((txt) => {
try {
let parsed = ical.parse(txt);
let events = parsed[2];

let result = [];
events.forEach(e => result.push(flattenEvent(e)));
resolve({events:result});
} catch(e) {
console.log(e);
reject(e.message);
}
})
.catch((e) => {
reject(e);
});
});
}

Basically — suck down the remote URL and parse using the library. As I said, there is a nice “object based” API that the library provides, but I found I could work with the initial data a bit easier. You can see where I just grab the third item in the array to get the actual events. I then “flatten” the data using flattenEvent. If your curious, the data is in a form called jCal, which has a specification: https://tools.ietf.org/html/draft-ietf-jcardcal-jcal-10. My flattenEvent function makes some assumptions that may not necessarily always work out well, but so far it's done ok.

I tested it by asking for Louisiana holidays:

wsk action invoke ical/get --param url https://raw.githubusercontent.com/gadael/icsdb/master/build/en-US/us-louisiana-nonworkingdays.ics -r

And here are the top five results.

{
"class": "PUBLIC",
"created": "2014-01-09T00:47:56Z",
"description": "",
"dtend": "1970-01-02",
"dtstamp": "2017-06-23T13:53:48Z",
"dtstart": "1970-01-01",
"last-modified": "2017-06-23T13:53:48Z",
"rrule": {
"freq": "YEARLY"
},
"sequence": 0,
"status": "CONFIRMED",
"summary": "New Year's Day",
"transp": "TRANSPARENT",
"uid": "b901ca08-d924-43c3-9166-1d215c9453d6"
},
{
"class": "PUBLIC",
"created": "2014-01-09T00:47:56Z",
"description": "",
"dtend": "1983-01-02",
"dtstamp": "2017-06-23T13:53:48Z",
"dtstart": "1983-01-01",
"last-modified": "2017-06-23T13:53:48Z",
"rrule": {
"byday": "3MO",
"freq": "YEARLY"
},
"sequence": 0,
"status": "CONFIRMED",
"summary": "Marthin Luther King day/Robert E. Lee day",
"transp": "TRANSPARENT",
"uid": "0ae8128a-e360-492c-b2bd-52ed0d6d06fd"
},
{
"categories": "-New Mexico",
"class": "PUBLIC",
"created": "2014-01-09T00:47:56Z",
"description": "",
"dtend": "1970-02-01",
"dtstamp": "2017-06-23T13:53:48Z",
"dtstart": "1970-02-01",
"last-modified": "2017-06-23T13:53:48Z",
"rrule": {
"byday": "3MO",
"freq": "YEARLY"
},
"sequence": 0,
"status": "CONFIRMED",
"summary": "Presidents Day",
"transp": "TRANSPARENT",
"uid": "17425d41-9ed3-4088-adad-4693d1bd44c9"
},
{
"categories": "Louisiana",
"class": "PUBLIC",
"created": "2014-01-09T00:47:56Z",
"description": "",
"dtend": "1970-04-02",
"dtstamp": "2017-06-23T13:53:48Z",
"dtstart": "1970-04-01",
"last-modified": "2017-06-23T13:53:48Z",
"rdate": "1970-02-10",
"sequence": 0,
"status": "CONFIRMED",
"summary": "Mardi gras",
"transp": "TRANSPARENT",
"uid": "7ac45e93-a684-4061-a0c7-948a89e358b0"
},
{
"categories": "Connecticut",
"class": "PUBLIC",
"created": "2014-01-09T00:47:56Z",
"description": "",
"dtend": "1970-04-09",
"dtstamp": "2017-06-23T13:53:48Z",
"dtstart": "1970-04-08",
"last-modified": "2017-06-23T13:53:48Z",
"rdate": "1970-03-26",
"sequence": 0,
"status": "CONFIRMED",
"summary": "Good Friday",
"transp": "TRANSPARENT",
"uid": "3c46243f-00f8-418f-94cf-4eda72ae7cb2"
}

So… that’s some data. Cool. What would I do next? When I first started thinking about this data, my first thought is that it could be a useful API for web apps. I’m a web developer so everything looks like a web-related source for me. Of course, why would I need serverless for that? I could run the iCal library in the browser — the only issue I’d run into is CORS — maybe. And I could always copy the iCal files to the same server as the app. But that’s really limited thinking.

By creating this as a serverless action, I’ve opened it up to any event source, web or not. How about an example of something completely non-web based?

Imagine a support service where every day, my process gets a list of employees responsible for IT work in case of emergencies. I could imagine a process by which after getting a list of employees, I could check each one’s home state against a list of holidays for that state and determine if that person is off today. It’s the exact same code, but I’m simply using it in a different context.

And this is something important to keep in mind here. Serverless isn’t just about building NodeJS apps simpler. Instead I’m creating a resource that can be used in multiple situations, both direct (web app making a request) and indirect (a process run on a timed schedule).

This is something I’ve talked about before, but I feel like it’s something that’s possibly not quite as evident.

p.s. You can find the source code for this demo here: https://github.com/cfjedimaster/Serverless-Examples/blob/master/ical/get.js


Originally published at www.raymondcamden.com on August 24, 2017.

Apache OpenWhisk

Apache OpenWhisk is a serverless cloud platform that executes code in response to events

)
Raymond Camden

Written by

Developer Experience for American Express. Serverless/Web/Node/cat developer and Star Wars nut.

Apache OpenWhisk

Apache OpenWhisk is a serverless cloud platform that executes code in response to events

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade