GunplaHub Update #3 - Deployment and Serving Images

This third update has a mostly to do with deployment. It's amazing how many free/cheap tools are at my disposal!

From my last post: My progress is currently in a private Gitlab repository. I also have a Heroku account that I’m not using. I like both services, as Gitlab has it’s own CI built in, I could just whip up a quick job that would run my tests, and (if tests pass) deploy my latest builds to Heroku. This way I get to focus more on development and less on DevOps!

Side note: It's been two months since I last worked on GunpaDoodles!

Table of Contents

1) Intro, Technical Decisions, What's Next

2) Slugs, Obfuscated Primary Keys

3) (Current) Deployment and Serving Images

4) Refactor and Document Often

5) Automation and SEO

Heroku

As a developer, I want to spend most of my time developing new features, fixing bugs, and making the app better. If possible, I'd like to avoid time sinks like DevOps work.

Deployment works like magic. With a properly configured app, all I have to is push to my Heroku git url.

It's also easy to hook up Gitlab CI and Heroku. Now, each check-in I do gets verified by an automated build, and releases the latest sucessful build into production.

The best part: I'm getting all of these for free!

Serving Images

Displaying toys doesn't just mean displaying meta data about them, but also showing the user what this toy looks like. With a small number of toys, I think I could have gone with serving these images from my Heroku instance (using WhiteNoise, since Heroku doesn't serve static files).

I have 800+ toys in my database, which means I could have 800 images, and 800 thumbnails to display! This could very well fit into Heroku's 500mb limit, but I'd rather a good infrastructure in place now while the project is still young (and no users :D).

I am hosting my static and media files on Google Cloud Storage. I have no reason for picking G over the very well supported S3, except that 2014 me somehow got my AWS account suspended.

Several services on GCP are free, so that's nice :) I'm well below the free tier's limit for Google Cloud Storage, so I think I'm only paying a fraction of a penny for each time I retrieve ALL my static files.

Google Cloud Storage's CLI tool gsutil is also pretty easy to use. First thing I did with gsutil was to make sure my assets weren't public. I don't want anyone somehow arriving at my bucket and rapidly retrieving assets, hurting my wallet in the process.

Wait, if my static files are private, then clients accessing my API wouldn't be able to display these images!

Thankfully, Google Cloud Storage let's me serve my files through signed urls. These URLs have an expiry time/date.

Example:

/my-bucket/images/nicolas-cage.jpg

Client wouldn't be able to load the image, because this file is private.

/my-bucket/images/nicolas-cage.jpg?GoogleAccessId=<SOME_ID>&Expires=<TOMORROW>&Signature=<SOME_LONG_STRING>

Client would be able to load the image today, but not tomorrow!

Integrating Google Cloud Storage to my Django app is as simple as using the django-storages package, adding my storage bucket's credentials, and calling manage.py collectstatic --no-input. Now, my app will pull my static files from my bucket!

SSL comes free as well!

What's Next

So, I have a fully functional API with tests and set up for continuous deployment. I feel that work on my API can be held off for now. It's time to write an actual client that would consume my API! I'm going to write a simple Web client that will do the following:

1) Display a list of all toys

2) Filter toys based on size, show they appeared in

3) Query toys using toy names

4) Pagination

5) (Optional) Sorting by latest price

Super excited to get started!

tags: gunplahub