How to deploying your API

Today I'm going to walk you through how to deploy your API using either Heroku or AppEngine! They're fairly similar services, but I wanted to give you a chance to use both and see what you prefer. By using two services I can also show you how different platforms expect a different file structure for your apps.

  • Heroku is a platform as a service that's designed specifically for serving applications. You don't need to have a credit card to create an API on Heroku, but you'll be limited by what's offered through the free tier.

  • AppEngine is part of Google Cloud and is also a way to serve apps. You do need a credit card to create an app on AppEngine, but once it's set up you can go to your appengine settings and set the daily spending limit to 0. This will keep you from being charged.

I'll start with Heroku, then talk about AppEngine and finally show you how to query your API using Python. :)

Heroku

Edit files on GitHub

For your conviencice, I've created an extrememly simple sample app on GitHub: https://github.com/rctatman/minimal_flask_example_heroku. You'll want to head over to GitHub, fork this repo and then edit the relevant files for your specific app.

Here's a quick guide to each of the files and information that tells you which to edit:

Files you'll put the code you wrote yesterday into

In yesterday's notebook, as the very last exercise we wrote two cells of code, each of which will be a single file.

  • serve.py: This is the file you should put the code from the first cell in; this is where you'll define the functions that will read in your trained models.

  • script.py: This is where you'll put the code from your second notebook. This is what will define the behavior of our different endpoints.

Files you'll need to add

If you are going to use a pre-trained model, be sure to add it to your repo so that you can read it in. If you like, you can store your models in a new file, but if you do this be sure to update the file path of the code that you read them with. So if you have a model called "my_model.pkl" in a folder called "models", you'll need to update the code that reads it in from this:

pickle.load(open("my_model.pkl", "rb")

to this:

pickle.load(open("models/my_model.pkl", "rb")

Files you'll need to edit

  • README: This is the file you're currently reading. You'll probably want to update this to have information about your specific API and how to use it.

  • openapi.yaml: You can relace this file with the specification file that we wrote on day one. (The notebook's here if you need a refresher).

  • requirements.txt: This file has information on what packages you use in your app. You need to make sure that you list every package you import and also gunicorn. If you remove the line with gunicorn or forget to include a package you import somewhere else, you'll get an error when you try to run your app.

  • runtime.txt: This file tells Heroku which version of Python to use to run your app. You'll only need to update this file if you pickled your model file using a different version of Python & that's causing your code to break.

File you don't need to edit

  • LICENSE: This file is the license your code is released under. If you don't include a license, other folks won't be able to reuse your code. If you fork this repository for your own work, you'll need to keep the license. I've used Apache 2.0 here because that's the same license as public Kaggle Kernels.

  • Procfile: This file is required by Heroku. It tells Heroku how to run your application. You probably don't need to change this file.

Deploy to Heroku

Once you've edited your files, you're ready to deploy to Heroku.

  • Create a new account or sign into your existing account

  • Create your app

    • Click on “create new app”

    • Give it a name & choose your region

    • Hit “create app”

  • Connect to GitHub repo

    • Click on the Deploy tab

    • CLick on Connect GitHub & search for the repo you want to add (make sure you've forked the repo; you'll only be able to connect to a GitHub repo you own)

  • Deploy your app

    • Next to “Manual deploy” hit “Deploy Branch”

    • If you hit “open app”, you should open a new browser page that points to the URL your app is served from. (Unless you put something at the endpoint "\" it will probably just be a 404 page.)

And that's it! Your app is live. :)

What if you run into trouble? If your app isn't working, click on the [MORE] button in the upper right hand corner, then on "View logs". This will show a detailed log of whatever went wrong.

AppEngine

For your convenience, I've created an extremely simple sample app on GitHub: https://github.com/rctatman/minimal_flask_example_appengine. You'll want to head over to GitHub, fork this repo and then edit the relevant files for your specific app.

Here's a quick guide to each of the files and information that tells you which to edit. Note that this is different from the files for Heroku; the two different services expect different file configurations.

Edit files on GitHub

Files you'll put the code you wrote yesterday into

In yesterday's notebook, as the very last exercise we wrote two cells of code, each of which will be a single file.

  • serve.py: This is the file you should put the code from the first cell in; this is where you'll define the functions that will read in your trained models.

  • main.py: This is where you'll put the code from your second notebook. This is what will define the behavior of our different endpoints.

Files you'll need to add

If you are going to use a pre-trained model, be sure to add it to your repo so that you can read it in. If you like, you can store your models in a new file, but if you do this be sure to update the file path of the code that you read them with. So if you have a model called "my_model.pkl" in a folder called "models", you'll need to update the code that reads it in from this:

pickle.load(open("my_model.pkl", "rb")

to this:

pickle.load(open("models/my_model.pkl", "rb")

Files you'll need to edit

  • README: This is the file you're currently reading. You'll probably want to update this to have information about your specific API and how to use it.

  • openapi.yaml: You can relace this file with the specification file that we wrote on day one. (The notebook's here if you need a refresher).

  • requirements.txt: This file has information on what packages you use in your app. It's currently empty becuase I didn't import any packages, but you'll need to include all the packages you use, one per line as show below. If you forget to include a package you import somewhere else, you'll get an error when you try to run your app.

numpy
pandas
future

Files you don't need to edit

  • LICENSE: This file is the license your code is released under. If you don't include a license, other folks won't be able to reuse your code. If you fork this repository for your own work, you'll need to keep the license. I've used Apache 2.0 here because that's the same license as public Kaggle Kernels.

  • app.yaml: This file tells AppEngine which version of Python to use to run your app. You don't need to edit this.

  • index.yaml: This file is required by AppEngine and tells it how to index the data you send to Datastore. Since we're not using Datastore, we can just ignore this file.

Deploy to AppEngine

Now you're ready to deploy your app! We're going to be interacting with AppEngine via Cloud Shell. You can use the GUI as well, but I personally like Cloud Shell. :)

Don't forget to sign into your GCP account or create one if you don't have one! You'll also want to set up a billing account you can connect your project to in order to build your app.

I know this looks like a lot of steps, but I've tried to be very clear so you know what to do at each step.

  • Copy your repo into your Cloud Shell VM

    • Either edit and use the button in the GitHub README OR

    • Go to the Cloud Shell (https://console.cloud.google.com/cloudshell/editor) and clone it yourself: git clone [GITHUB-URL]

    • Move into the repo by running cd [NAME-OF-REPO] in the black console at the bottom of the screen, which is where you'll run all the commands from here on out. (You'll need to replace [NAME-OF-REPO] with your actual repo.)

  • Launch your app locally (helpful for testing)

    • Use this command to test deploy your app: dev_appserver.py ./app.yaml

    • Once you see output like: "Booting worker with pid" in the command line, you can see your app by hitting the button that looks like <> in a browser window at the top right hand side of your screen. This will open a new tab running your app. If you haven't put anything at the "\" end point, this will just a 404.

    • Use CTRL + C to close your app

  • Create a project & enable billing.

  • Launch the app!

    • Deploy your app by running this command:

      • gcloud app deploy ./index.yaml ./app.yaml

    • Pick a region (I'd recommend one closer to you to reduce latency)

    • Enter "y" when asked whether you want to continue

    • After it's finished deploying, your app will be at the URL: https://[YOUR-PROJECT-ID].appspot.com/

  • You can query your app directly from Cloud Shell! :)

    • Run these commands to query your app, replacing the [text in brackets] as applicable for your project.

      • python

      • import requests

      • requests.[METHOD]('https://[YOUR-PROJECT-ID].appspot.com/[YOUR-ENDPOINT-NAME], json=[JSON-TO-SEND]).json()

In [1]:

requests.post('https://api-test-project-236423.appspot.com/api', json=input_text).text
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-bb1dd8785bb7> in <module>()
----> 1 requests.post('https://api-test-project-236423.appspot.com/api', json=input_text).text

NameError: name 'requests' is not defined

Querying APIs using requests

Ok, now that you've got your app up and running, how do you actually query it? Probably the simplest way to do this from Python is using the requests library. The anatomy of a request is like so:

requests.method

This will send a request to your API and, hopefully, return a response. If it works, you'll probably just see the response code output:

<Response [200]>

In order to get the data that was returned, you can append .json() to parse any JSON that was returned or .text just to see the raw strings.

Here are some example queries for the sample app I've talked about in my notebooks so far. (Note that I'm only using the free tier of each service to serve these, so if people make a lot of requests and I hit my quota, they'll stop working.)In [2]:

import requests

input_text  = "Pandas is my favorite library. I don't like numpy as much as future."

# this queries an app I already have running on Heroku
# code: https://github.com/rctatman/flask_example_heroku
requests.post('http://kaggle-test.herokuapp.com/extractpackages', json=input_text).json()

Out[2]:

[['pandas', 0, 6], ['numpy', 44, 49], ['future', 61, 67]]

For the AppEngine version, I called my endpoint "api" instead of "extractpackages" and I'm honestly just too lazy to change it at this point. Otherwise it looks pretty much the same, but with a different URL.In [3]:

# and this queries a pretty much identical app running on AppEngine
# code: https://github.com/rctatman/flask_example_appengine
requests.post('https://api-test-project-236423.appspot.com/api', json=input_text).json()

Out[3]:

[['pandas', 0, 6], ['numpy', 44, 49], ['future', 61, 67]]

And that's it! Over the last three days we've:

  • Designed an API and written a specification

  • Prepared our code & models to be put in a Flask App

  • Written the app itself

  • Deployed and used our very own APIs

I hope you found these notebooks helpful and learned something new about APIs. I'd love to hear about what you all built in the comments!

Last updated