The opinions stated here are my own, not those of my company.
New York City is back! COVID-19 cases continue going down, vaccinations keep going up, and things are reopening.
It’s admittedly weird to get back to something like normal. The past year cannot be forgotten, nor can the personal changes be shed. At the same time, I am excited for a fun summer and social events.
There are a lot of events happening: concerts, theater, poetry, and more. In years past I would traverse a list of bookmarks, each of which would be the events page for a particular venue. I would scroll through each page, identify any events that were interesting, and copy the event details to a Google Calendar. This process would occur every month, with an ever growing set of links.
Given that events constantly change, with more added or modified, it was not easy to keep track. It was also a time consuming process, with me having to navigate through a dozen unique interfaces. Then, I would need to take time to copy relevant details to another calendar, which was a manual step.
Why does every website post their events in a unique design? It’s not easy to follow, nor is it very accessible. There is in fact a better way to host a list of events. iCalendar, RFC 5545, is a technical standard to represent events. It’s actually already used in most calendar apps including Google Calendar, Outlook, and probably on iOS. Using a machine-readable interface for events, I would be able to browse using any app I wanted in a central interface rather than having to spend time navigating complexity.
Of course, Public Theater doesn’t have an iCalendar format for their events, so I had to make one. Using the Cheerio library, I built an endpoint that will scrape the Public Theater website, parse the HTML, and output a calendar.
As you can see, the format is pretty straightforward. Calendar-wide metadata is presented after
BEGIN:VCALENDAR . Events are started with
BEGIN:VEVENT and end with
END:VEVENT with each metadata field being represented as a key-value pair on newlines.
The HTML is parsed to get the critical information about each event like the title, time, and description. In my endpoint, I place this information into a specific data structure and then place that data into an array.
A follow-up function in the endpoint translates that data structure into the iCalendar format.
In a standardized, machine-readable format, I can import these events and view them directly in Google Calendar rather than having to go to the page itself. I don’t even need to request a list of events, they’re just available to me.
If I sent the endpoint to you, you may open it up in the calendar app of your choice. Windows 10 has a native calendar app that also accepts this format.
Since it’s an endpoint, and not a manual copy, it will regularly be refreshed. The
LAST-MODIFIED date represents the time the endpoint is called, because each call of the endpoint will fetch all of the events again. (This lack of a cache is probably not optimal, but works well enough for a proof-of-concept).
My calendar will reflect changes and additions without manual effort.
Because of the way I’ve designed my endpoint, I don’t need to limit it to just one venue. There are many other places that are beginning to host events again like Lincoln Center and the new Little Island amphitheatre. Again, each website has a completely different navigation scheme.
Each events page is implemented as a separate module. Each module is designed to output events with a standardized data structure. The endpoint requests the data from each module in a promise, then converts the data into the iCalendar format which it then outputs. Using a header type of
text/calendar , the browser knows how to handle the response.
As shown in the snippet above, I build an array of events using TypeScript for type-safety regarding the types of each attribute and required fields.
obtainFeed async function then returns an
EventsFeed which is then used by a central function to format the events. Every venue can easily comply with this contract I’ve set up, making it relatively easy to extend this with additional venues over time. Regardless of how they implement the HTML, or if they use a JSON endpoint, this approach can generate an iCalendar output without affecting existing modules.
My endpoint further supports a modular approach by accepting desired calendars as an array query parameter. One can add the venues they want, or just use
?c=all for all of the available ones. Additionally, adding
&debug=true in the URL will sent out plaintext that can be read in the browser for easier debugging. I’m using Cloud Functions for Firebase for the easy deployment runtime.
Now all of these events are publicly available at this Google Calendar link. Of course, Google also hosts an iCalendar version as well. I’m sharing the hosted version instead of my own just to reduce the number of function invocations.
I would much prefer each venue to host their own iCalendar. There’s a lot of value in using web standards. These standards are more useful than reinventing the wheel, and allow for better, more flexible interfaces compared to whatever any individual can do themselves. The standards are more portable, making it much easier to share and view events in apps that the end-user is already using.
There is also a way to embed these properties into a webpage, through the standard Event schema. In my experiments with HTML parsing, I did see a few vendors who used a few parts of this schema, but it wasn’t complete. The value of these schema is to make it easy to crawl and get events, and then surface those events to the user in other applications.
Web designers are probably not familiar with these standards enough to add them to their sites, nor may they see the benefit. It can be easy to look at Facebook Events on your page and see exactly how many people you’re reaching. But the true value of standardized components is being self-reliant, open to any application rather than having to manually market events in numerous channels. That’s the beauty of the web as well, having an open standard approach that lets one grow on their own terms rather than being reliant on large services.
Anyway, to sum up, iCalendar is neat and it’s a shame it’s not more widely available.