Making QR codes with cloud functions

In a blog post I almost missed earlier this year, Jeremy Keith points to an interesting use case for print stylesheets, namely putting QR codes on the printed versions of, well, just about anything on the web. Jeremy rightly lamented Google’s deprecation of the Charts API. The existing Charts API is a simple service that lets you throw data at a URL and it renders it server-side into an image… and Google have decided that this is far, far too boring and old fashioned and it must now be done client-side.

Now, you can, of course, run a QR code generator on your server. Having been infurated by Google having deprecated various other APIs, it’d be pretty sensible to not trust them. So, the obvious answer is you could write some code and add it to your server and have it generated server-side.

But… what about those of us who run websites purely on a static site generator host like GitHub Pages or Netlify? Or who just don’t want to have to modify a working site’s back-end code to switch over from Google’s Chart API. In Jeremy’s example, he’s using CSS generated content to add the QR code to the print stylesheet. This seems like a great use for (buzzword alert!) serverless. Now, serverless is a very silly buzzword dreamed up by someone from the consultant class who loves coming up with terrible names, so I promise I won’t use it any further. Your code obviously runs on a server. It just means it runs on a server that someone else manages.

Amazon call it a ‘Lambda Function’. Google call it a ‘Cloud Function’. Microsoft Azure call it simply a ‘Function’. But none of those are very descriptive, because, well, anyone who writes any kind of programming language generally writes functions pretty much all the time in much the same way as anyone who writes English writes paragraphs, and we thankfully don’t call our blogging software “Cloud Paragraphs”. (Someone will now, I’m guessing.)

What these things really are: ways to fairly simply deploy a small blob of code serving one single HTTP(S) endpoint on a platform where everything else is taken care of by the platform provider. This makes deploying pretty easy, and it also simplifies scalability. It also can reduce cost: you are paying for the fractions of a second that your code is running on Google or Amazon or Microsoft’s servers, rather than paying for a $5 or $10 (or $100) a month server to sit idle not doing much when your site isn’t busy. It certainly reduces the amount of time one spends maintaining servers. Hence why some very buzzword-addled people call it “serverless”. There’s a server, obviously, you are just paying for it in tiny fractions of a cent per millisecond rather than in dollars per month.

Cloud functions are really good if you’ve got a small, modular problem that you want to fix, and generating QR codes is an almost canonical example of a nice little modular problem— it doesn’t change much, nor does it involve databases or user sessions or much of anything else. I wrote a tutorial post back in March on using Google Cloud Functions with Nexmo showing how to get set up with Google Cloud Functions that serves as a useful precursor for those unfamiliar with them.

Code

Last night, I cranked out a tiny Python function to make QR codes. This probably took about 15–20 minutes to write using Python’s qrcode module. Why Python? Because I know Python. I could have done it in a whole variety of different languages. For a lot of people, Node.JS will probably be their preferred language, but you can really take your pick.

The get_qrimg function follows the same API as Flask’s Request class. If you’ve written a Flask app, you can write a Cloud Function in Python. Same with Google’s support for Node—if you know Express, you can use it.

Resource abuse

If literally every single request is costing some tiny fraction of money to process, how do we stop abuse?

There’s a fairly simple answer here. Just make it so your function can only return QR codes for URLs on your own site. Just plumb in a little function like this to your code.

Nobody else is likely to use your QR code generator for very long if they are getting back empty and non-functional QR codes for any URL other than your website. You could substitute in the URL of a high quality YouTube video for their delectation if you prefer.

SVG and making files tiny

What I’ve hacked together is in Python. As I said, I’ve done this because I like writing Python and would rather write Python than JavaScript. The Python module has a way to produce SVGs. I experimented with this, but left it out of the final version above.

I wanted to see how SVG performance lines up compared to PNG. (We all want nice, light webpages, right?) Let’s look at the numbers.

  • SVG unoptimised: 11,177 bytes
  • SVG unoptimised (gzipped): 3,090 bytes
  • SVG optimised: 4,622 bytes
  • SVG optimised (gzipped): 1,280 bytes
  • PNG: 547 bytes
  • PNG (gzipped): 570 bytes

I ran the SVGs manually through Jake Archibald’s SVGOMG, a browser-based SVG compressor/optimiser. One fairly compelling reason to use Node.js instead of Python is you can use the svgo library, on which SVGOMG is based. But looking at the numbers above, PNG seems pretty great, so I’ll just use that rather than SVG.

Conclusion

How does getting Google to host an API for us to use to generate SVGs get us away from the “Google might take away the API” problem we started with? Easy: you are paying a tiny amount of actual money for it, and I’m guessing Google, Amazon and Microsoft might be rather hastier about turning off or screwing around with a service that (at least some) customers are paying for than something that absolutely nobody is paying for like the old Charts API. That old adage about “if you aren’t paying, you aren’t the customer, you are the product” applies.1

Cloud functions present a really great way for people who run their own personal sites to have small amounts of back-end programming offloaded, along with the server management. I hope I’ve demonstrated that they are a viable approach if you’ve got a third-party API that’s being deprecated (sunsetted, perhaps?),2 you can use them to switch in an alternative.


  1. Of course, even if you do pay, you are still the product. [return]
  2. Once Google deprecate the whole Charts API, maybe matplotlib would be a useful thing to put into some cloud functions. [return]