A spiderweb! For Webmention! Get it? Okay, yeah. Sorry.
So I hosed a local copy of my mentions feed the other month. What’s my “mentions feed,” I hear you wondering?
Whenever somebody shares a reaction to something here — like, reshare, reply, mention — that reaction gets sent to Webmention.io. There are more moving parts than that, of course. Bridgy aggregates reactions to my announcement toots and tweets and sends those to Webmention. It shows in my mentions feed as a reaction to site content when someone reacts to a relevant tweet.
Sometimes folks even post mentions, replies, and reactions directly to the Webmention endpoint. Mostly it’s just social media reactions, though.
The Webmention.io API lets me gather all of these reactions.
Let’s acquaint ourselves with the important parts of this API. You’ll need your API token, which can be found in the Webmention settings once you sign up.
Reading the feed with HTTPie
I’ll use HTTPie for my little exploration. I like the way it works.
Getting recent reactions
We mainly care about the mentions endpoint. Hand it your domain and API token, and it will send you the 20 most recent responses for your site.
HTTPie’s double-equals == syntax means “make a query string,” so I end up with something like this::
When http fetches that URL, I get back a JF2 feed that looks something like this.
What’s JF2? It’s obviously JSON. Maybe something to do with JSON Feed? Similar, but no. JF2 is a JSON format for microformats2. The mnemonic I’ve been trying to drill into my head is “JSON (micro)Formats 2.”
It’s not a very good mnemonic.
Each entry summarizes the reaction, including which of my posts they were reacting to. That’s kind of important. Most recently, Twitter user @junkw retweeted my announcement about adding a note from Org mode.
NOTE
There’s also a .json endpoint for every feed that presents a different structure for mentions. I prefer it, because it contains fewer wm-* fields. But the documentation uses JF2, so that’s what I’ll do.
Checking for new reactions
Maybe I’m checking again later and only want to see the new reactions. I request mentions received since the value of the wm-received field in the last entry I have.
Well, yeah. That makes sense. I don’t get the kind of traffic where you’d expect fresh reactions every time you check.
Fetching the oldest reactions first
As I mentioned at the start, my site is a little broken. I need to rebuild the full list of reactions so my Hugo site can work with a complete record. To do that, I should probably start from the oldest mentions and work my way forward.
Rather than the default sort-dir of down, I specify up.
I only get 20 results by default, though. Here. Let’s make jq show us. Here’s a default page.
Handling result pagination
I can specify how many responses I want in each response with the per-page parameter. With per-page set to 100, I get a hundred entries.
Of course, if there aren’t a hundred entries to fill the page, I only get what’s available.
The page parameter — which starts at zero — lets me step through the feed in batches.
Right. That’s Bridgy catching a Twitter thread. At least I can see the full conversation from my site. Or I will once I’m done fixing everything.
Bonus: checking for reactions to a specific post
I could get a JF2 feed for specific URLs on my site if I was so inclined.
I deal with my site reactions in bulk so they can be incorporated in the Hugo build. This could be handy for JavaScript-driven update on reactions since the site was last built and pushed, though.
Rebuilding the local mentions file
Now I want to take what I learned about the API to build a local copy of my site’s mention history. Let’s step away from HTTPie and the command line before I try something dangerous.
The Requests library for Python can help me build one list of Webmentions.
This gives me the first requirement for rebuilding my mentions: an intact historical record, up to the current moment.
Intermission
Time to pause.
Why? Why not just use this JSON as a Hugo data file — let it filter through finding relevant mentions for each post?
Short answer: that’s how I got myself into this mess in the first place. I want to take a more careful approach this time.