Private resources with ElasticSearch and Tire

I’m adding private channels to Player FM and one consideration is search results. Tire’s activerecord does a great job at making updates transparent, but in this case some manual overriding is required.

Importantly, this allows the user to switch privacy on and off, and the index will automatically be created and deleted. I initially considered using a “_changed?” check, but realised it’s unnecessary as ElasticSearch’s remove operation is idempotent. In other words, it’s safe to remove an already-removed item. Yes, the call could be avoided by checking if the resource is already private, but the call is cheap, a fraction of the cost incurred if the channel was public anyway (i.e. it would have to be re-indexed).

There was some talk of a “should_be_indexed?” method which any record could override. I think it would be perfect for this use case – it’d just be a case of a one-word return value (public?) but alas, it wasn’t added. As the code above shows, though, it’s pretty simple to DIY.

image by Zebble

Testing ETags: A Little Gotcha

TLDR: ETags have quotes, escape them when issuing requests.

I’ve been using HTTPie to test some conditional caching I’ve been setting up on a JSON API. It’s much more intuitive than Curl, very recommended.

A funny thing about ETags is the values are surrounded by quote marks, unlike most other string-based HTTP header values. (And even better, this being the web, there’s much flexibility in implementations, even if the quotes are required by the standard.) So a response looks like:

HTTP/1.1 200 OK
...
ETag: "avm3pvp34vpoktcbd18db4c"
Normal-Header: some value

Having added conditional caching support on the server, I was now looking forward to reaping the reward and seeing 304s show up client-side. Hustling for the cacheworthy 304 Not Modified response, I tried this:

http -phH localhost:3000 If-None-Match:avm3pvp34vpoktcbd18db4c (Wrong!)

And I kept getting 200s, meaning a fresh response every time. Server wasn’t recognising the value because quotes. So the correct thing to do is:

http -phH localhost:3000 If-None-Match:"avm3pvp34vpoktcbd18db4c"

And now the server recognises it as the same ETag. Satisfying 304 is Satisfying.

(Of course, this was working all along in the browser. I figured it might be working because of the other conditional caching mechanism – timestamps (Last-Modified and If-Modified-Since headers) – even though the ETags were apparently different. But it turned out the ETags were indeed right as the browser, unlike me on the command-line, knew how to actually send them.)