There’s been a lot of activity recently around Microsub, a standard API for feed reader clients to talk to servers. Many existing readers have APIs, so I’ve been thinking about a bridge that would translate those APIs to Microsub, so that clients like Together and Indigenous could use traditional services like Feedly and NewsBlur as their backend.
The two basic models for a Microsub bridge are:
- Require a user account on the service. Use it to store all user data: subscribed feeds, read state, channels, mutes, blocks, etc. The bridge would let users OAuth into the service to authorize their account. The bridge would simply translate all Microsub requests to API requests that fetch and return the user’s data.
- Use the service as just a feed fetching and processing tool. The bridge would create and own all user accounts and data.
I’m more interested in #1, so I’ll forego discussing #2 here. Here’s a design sketch:
- The bridge would serve a Microsub endpoint. It could support the full fledged IndieAuth discovery flow, or it could just OAuth users into the service and then give them a token to manually paste into their client. This token could be the service’s token directly, or it could be a separate token that the bridge mints and manages.
- If the service has API auth scopes, the bridge should translate Microsub’s scopes to them as closely as possible.
- User profile URLs could come from the service directly, if it has them, e.g. snarfed.newsblur.com. Otherwise, the bridge could generate and serve its own placeholders.
timelinerequests would be translated and passed through to the server. Response items would be translated to JF2 (Microsub details).
unfollowrequests would also be translated and passed through, assuming API support. (Common but not universal.)
- Channels, muting, and blocking may or may not be supported by the service. If so, they should be translated; otherwise requests for them should return errors. (And probably skip channel ordering, at least to start.)
- Likewise, paging may or may not be supported either. If it’s not, response objects should omit the
pagingfield, and requests with
before=should return errors.
- Probably skip
preview, at least to start.
- Read state is brainstorming, and has some experimental implementations, but hasn’t been fully specified yet.
At a high level, this is very narrow functionality. This bridge needs to accept Microsub HTTP requests, translate them to reader API HTTP requests, translate the payload from the API’s format to Microsub’s, and return that translated response. That’s it. I just need an HTTP translator/convertor that lets me map incoming and outgoing query parameters and payloads.
Apigee’s API Management product looks like it would fit the bill, but their pricing clearly isn’t aimed at hobbyists. The free Evaluation tier could still work, though, as long as it’s not limited to 30 days.
Cloudflare Workers look awesome, and are led by an old colleague of mine who I know does great work. They’re allowed to run for upwards of 15s wall clock time, but only 5-50ms CPU quota (based on plan), which is a bit worrisome. We’ll see.
I was originally tempted to use Zapier. I’ve used it before, and it’s great. The webhook, code and possibly formatter integrations should do exactly what I want, without requiring any server admin or code beyond just the mapping.
Sadly, Zapier is probably too expensive. Every single HTTP request would cost something like 2-4 “tasks,” which don’t come cheap. The free tier only includes 100/month, and the $20/month plan only bumps that up to 3k.
IFTTT, on the other hand, is probably too limited to work at all. It supports webhooks, but no custom code (other than the way too heavy and expensive partner platform) or other way to transform response data itself.
Existing readers and APIs
Here are some major existing online readers with APIs we could use. Thanks to Replace Reader for its comprehensive list.
|Feedly||entries||subscriptions||categories, tags, streams||profiles||search||continuation||markers|
|Feedbin||entries||subscriptions||tags||X?||saved searches||rel-next/prev||unread entries|
|Inoreader||stream contents||subscriptions||folders/tags||user info||active searches||
||unread counts, mark read|