I’ll be trying something different with this blog post – logging my efforts while going after a goal. It might not be riveting reading but I’m looking for ways to increase my output in 2020. And Happy New Year!
I’ve been enjoying the very cheap and surprisingly functional web hosting from Siteground, but one way they keep the cost down is by using software over a decade old and denying install privileges on the machines (that I can ssh in 24/7 for less than the price a beer a month still amazes me). You won’t be able to FTP a copy of Miniconda (trust me, I tried it), so you’re stuck with the LAMP framework. But at the same time, you have powerful data science functions written in Python. What do you do?
The rest of this stream-of-consciousness style blog article explores the use of Heroku to solve this problem. Though I do not explicitly show a website requesting output from Python data science modules, I believe all the pieces are in place by the end.
Parthiban’s REST API via Heroku Tutorial
Previously I wrote about deploying data science apps on Heroku, and while I was very impressed with the service and how it let me work with common data science Python dependencies like statsmodels, I never exposed the app to the outside world. Today, I found this great looking article from Parthiban Sudhaman that promises a walk-through of developing a REST API in Python and deploying it on Heroku. Let’s try it out.
Parthiban recommends creating a virtual environment and installing the following dependencies:
- Flask-RESTful (
pip install flask-restful), a tool for building REST APIs and an extension to the web framework Flask.
- Gunicorn (
pip install gunicorn), a Python WSGI HTTP Server for Unix. It does not look like this runs on Windows.
Glancing at my first Heroku article, I realize need to get the Heroku CLI. Given the limitations of Gunicorn, I’ll install this on Windows Subsystem for Linux (WSL). But the default way of installing the Heroku CLI on Ubuntu, Snap, does not work with WSL at the time of writing. This command will install it on WSL:
curl https://cli-assets.heroku.com/install.sh | sh.
Trying the simple REST API
Next, I create my own version of todo.py from Step 4 of the article, and note that the sole import is
Resource from the
flask_restful module. I learn that the name of the API game here is to inherit from this abstract class
Resource, so that your subclasses will be able to do real things with HTTP. Here’s the docstring from the Resource class:
Represents an abstract RESTful resource. Concrete resources should extend from this class and expose methods for each supported HTTP method. If a resource is invoked with an unsupported HTTP method, the API will return a response with status 405 Method Not Allowed. Otherwise the appropriate method is called and passed all arguments from the url rule used when adding the resource to an Api instance.
When Parthiban creates the subclass
Resource, it’s not immediately clear what specific functionality is coming from that parent class. After fixing some spacing issues, I was able instantiate a
Todo class locally and run the
get() method, but the
put() method returned an error about ‘request’ not being defined. Let’s keep moving.
Realizing that I had forgotten to store my todo.py in a folder called “resources,” I created that so that app.py could import it from one level beneath (the name of the base folder holding app.py and resources doesn’t seem to matter). I ran the contents of app.py in iPython and was able to see the REST API work in my browser:
Well I’m already happy. But this won’t do much for me if I can’t host it somewhere. On to Step 5.
Getting the Rest API onto Heroku
The following text goes into a file called “Procfile” in the root directory of this app (where I can see the resources) folder.
web: gunicorn app:app
The Procfile documentation shows that “web” is the process type and “gunicorn app:app” is the command to be run. It’s probably not a coincidence that our root python program is app.py and the Api class being instantiated is named “api” as an object, but I don’t know for sure.
I only add “gunicorn” and “flask-restful” to my requirements.txt file (in the same level as app.py), and it turns out this will be enough. I also omit the runtime.txt file without consequence.
Starting with the command
heroku login, I followed similar steps to Parthiban, but I diverged somewhat. Here are the steps generally laid out:
- Log into Heroku via the CLI (
- Create the app with the Heroku CLI (
heroku create) and save both the web address ending in “.git” and the URL.
- If the folder you’re working in isn’t already a git repository, make it so with
- If you don’t already have a remote that’s set to address copied in the second step, create one now. (This may happen automatically if you run
heroku create. I should find out!)
- Add all relevant files, commit, and push to your Heroku remote.
Pushing code to the Heroku remote is what kicks off the magic, and I just watched some happen in my Terminal. (It really does feel like magic to me.)
It’s time to test the API. If you forgot to save the URL you can get it with
heroku apps:info in the CLI. Add “/todo/1” at the end and see what happens:
Parthiban’s tutorial deserves more than 12 “claps”; people are just missing out. It lays out an easy to follow set of steps for getting started with Python REST APIs hosted internally. Thank you Parthiban!
Combined with the techniques I used in Data Science Apps in the Cloud with Heroku, there’s no reason to think this approach wouldn’t work with packages such as statsmodels. There’s a database featured there as well. I believe I have the elements for incorporating powerful data science functionality in a cheaply hosted website, but we’ll soon see.
To many good tutorials in 2020!