On Thursday, Aaron noted an idea for a service that would, given a URL, return the profile photo associated with the h-card on that URL. I found the idea intriguing, noting my interest in building it. I agreed that it would be great to have an API to call to retrieve a photo, similar to Gravatar but using h-cards.
After reflecting on this idea for a bit, I decided to create a version in Perl. I try to procactively challenge myself to use programming languages other than Python for tasks like small web applications to help me build my skills without taking on too great of a task. I called the project avtr.dev.
When I embarked on this project, I started off on a tangent: I wanted to build an endpoint discovery function. Given a URL, this function should return all of the "link" tags in the HTTP headers associated with a request response, as well as the "link" tags in the HTML response body. This tangent was relevant to another goal, however: allowing me to retrieve icons from favicons as a fallback.
Therein lay the growth of this project, from an idea for a h-card avatar service to an API that would do additional discovery to try and find an icon reflective of the given website.
While I was testing the endpoint discovery method, I ran into a problem. I noticed that URLs were sometimes "favicon.ico", which is not helpful for most use cases. I didn't want users to have to do canonicalization -- transforming part of a URL into a full URL -- so I decided to write a function that would transform partial URLs into full URLs. The end result was that instead of returning "favicon.ico" for a site, "http://example.com/favicon.ico" would be returned.
After working on the endpoint discovery method, I created a new function that makes use of the
Web::Microformats2 Perl package. This function looks for a h-card and finds the photo associated with the h-card, if one is available.
At this point, I had three steps of logic:
- Search for icons in HTTP headers.
- Search for icons in HTML headers.
- Search for a h-card photo.
I decided to add two more steps:
- Try to retrieve a Gravatar photo, if one is available. This is only available if a user provides an email address, however, since Gravatars are scoped to email addresses rather than domains. Implementation for this is still in the works.
- Try to retrieve a GitHub profile photo, if a rel=me link was available to a GitHub profile. Retreving the photo is done using the trick where appending ".png" to a GitHub profile URL (i.e. https://github.com/capjamesg.png) returns the user's profile photo.
This logic is executed when you make a GET request to the root project API with a URL whose avatar you want to retrieve.
With some tinkering, I now had an avatar service that let me retrieve icons for a range of domains. I deployed the API, alongside a landing page from which you can query the API, to avtr.dev. It took me some time to think of a concise domain name that was not expensive. All of the code for this project is available on GitHub. Feel free to deploy your own version of the API or make changes to help make this one better! I am eager to improve this project so that avatars can be retrieved in more cases.
Comment on this post
Respond to this post by sending a Webmention.
Have a comment? Email me at firstname.lastname@example.org.