Skip to content

behemothdan/magicqrcode-ui

Repository files navigation

MQR

Overview

This is a simple API and UI designed to allow users to provide a list of links to Magic: The Gathering deck lists and then generate a printable file of QR codes that they can print out and put on deck boxes, folders, or wherever they might want to have an easy way for folks to see their deck lists.

The Code

The implementation os pretty straight-forward. I use Express.js to scaffold the API. I added PDFKit and QRCode for the generation of the printable file the user generates. It should handle any number of given deck links in a single API POST request.

It also accepts an optional string for the deck title/Commander/etc if they wish to provide that. It also accepts a string for a HEX value if they want the QR code and label to be in a different color.

The UI

The UI is hosted in an S3 bucket and served from a CloudFront distribution. I used an SSL generated by AWS since it's free. The origin is set to the S3 bucket. Most of the behaviors are set to default with http traffic being routed to https. Because security in my application with no database.

The API

The API is set-up to be deployed from a Lambda and sit behind an API Gateway. Make note that a serverless deploy still leaves Typescript files behind and when defining your Handler it has to point to the dist folder in most projects because that is where the build JS file is going to be in order to do something like dist/server.handler or index.handler or whatever you name your main file.

The Cloud Set-up

This was far more complicated than I was hoping it would be.

You need to add a module.exports.handler = serverless(app) to your main file with some additional configurations which we will cover for streaming back certain types of content. Most of the configuration is fine with the default settings within the lambda once you connect it to the API Gateway.

For this API we proxied the entire API by adding a resource to the API Gateway that was /{proxy+} so it would handle all requests to the lambda. Most of that set-up is fairly standard although we did delete the OPTIONS method that was created since we didn't need it and it was causing errors on certain requests.

The big issues were binary content types. In order to avoid having to store PDFs and then server them back to the end user, we streamed the generated file to the user as it was created. Whiched worked great locally and testing it locally with Insomnia. The problem was how API Gateway handles binary media types.

We had to add application/pdf in the API Gateway Settings under Binary Media Types. In addition we added two headers to the UI request: 'Content-Type': 'application/json', 'Accept': 'application/pdf' The Content-Type was just indicating that our POST method was sending JSON however the Accept indicated what kind of content we were willing to receive back from the API.

In the API we added 'Content-Type': 'application/pdf' as one of our headers in our response. You can vbiew this in generateqr.ts.

The last bit was modifying how we exported our serverless configuration. The actual end result for packaging up our serverless looked like this:

module.exports.handler = serverless(app, {
   binary: ['application/pdf', 'application/json']
});

When we have all the pieces within our code and configured within our API Gateway so it knows not to send it back with the wrong encoding, the user can successfully receive a generated PDF from our API with their QR codes.