Talk given to full stack cohort at Galvanize/Boulder on December 20, 2016 about building APIs with Python / Flask.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

11 KiB

Your first Python REST API server

In this tutorial you will learn how to make a simple HTTP/REST API in Python 2.7 (or 3.5). When you're done you will know about:

  • how to install/verify your Python installation
  • how to do a basic package installation with pip, Python's package manager)
  • a few common Python data structures (notably Python objects, dictionaries, tuples, lists)
  • how to use the json module in Python
  • how to install the Flask microframework for Python
  • how to build and run a basic API in Flask

ADDITIONAL RESOURCES

What Where Why
A nice primer on Python decorators https://realpython.com/blog/python/primer-on-python-decorators/ You might want to get a little under the hood on how the routes (and other) decorators work.
Resource modeling - the RESTful way https://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling Can't get enough of REST?
A thorough intro to RESTful APIs https://codeplanet.io/principles-good-restful-api-design/ This really nails the full spectrum of concerns in a nice way, but get some coffee before you start.

STEP 1: Environment check

You will minimally need Python 2.7.1x for this tutorial. Most if not all of the code will work in 3.5.x as well, so feel free to use that moving forward.

CHECK YOUR VERSION OF PYTHON

  1. open terminal and type python -V

     $ python -V
     Python 2.7.12 :: Anaconda 4.2.0 (64-bit)
  2. execute pip install flask

  3. check to see if you have the json library installed

    $ python
    Python 2.7.12 |Anaconda 4.2.0 (64-bit)| (default, Jun 29 2016, 11:07:13) [MSC v.1500 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    Anaconda is brought to you by Continuum Analytics.
    Please check out: http://continuum.io/thanks and https://anaconda.org
    >>> import json
    >>> exit()
  • If this returns an error please execute pip install json.

Step 2: Build Your First Example App

We're now going to build our first functional app. It isn't going to do anything yet -- we just want to make sure that we can see that everything is looking good in our environment.

  1. Open your favorite editor and create the file app.py.

  2. Write the following code in your file and save it:

    # -*- coding: utf-8 -*-
     from flask import Flask
    
     app = Flask(__name__)
    
     if __name__ == "__main__":
         app.run()
    
  3. Go to your command line and type:

    $ python app.py
    

    You should see the following:

     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
  4. Hooray! You have your first Flask app, test it by opening your browser and pointing it to localhost:5000 (except if you don't see that last line * Running ..., then something is really wrong!)

    1. NOTE: You haven't implemented any endpoints/routes, so you should get HTTP/404 when you hit localhost:5000. This is the correct behavior.
    2. The default port is 5000, which can be changed later.

Step 3: Let's dissect what is going on ...

line by line now ...

from flask import Flask

This is a required import to get any basic Flask app running ... don't forget it, and don't linger on it.

app = Flask(__name__)

This variable is necessary to initialize the Flask app -- it is the Application Object. We're giving the name __name__ because we are running this application as a standalone in a single file (app.py). You can read more about how Python handles application and module name spaces, but if a file you create is run from the command line, its application __name__ attribute will be set to __main__ (unless overridden by the developer, but that is not a typical move in Python, so don't go playing footsy with it until you know why you might want to do so!)

if __name__ == "__main__":
    app.run()

This last bit of code tells Python that if this file is run from the command line (as opposed to being imported as a module), then execute the Flask application method run(), which starts the HTTP server (read the docs carefully if you're deploying in a production environment).

Step 3a: Let's make a few quick changes

Change the port

Let's change the port to something like 5200 using the port parameter of the Flask.run() method like this:

if __name__ == "__main__":
    app.run(port=5200)

Change the host ipaddress

The default parameter for the run() method is indeed the IP of your running server (which defaults to 127.0.0.1). You can set it to your fixed IP or use 0.0.0.0 to make it externally available.

Let's put your fixed/assigned/DHCP address in first (remember this may change depending on what network you are on):

  • Get the IP of your machine with ifconfig (on *X) or ipconfig on (Win*):
    $ ifconfig
    

and make the change accordingly:

if __name__ == "__main__":
    app.run(_your_ip_address_, port=5200)

Set DEBUG mode ON

Finally, let's make sure we run in debug mode so if anything crazy happens, we can find out what ... using the debug parameter makes that a snap ...

And now update your app.run() accordingly:

app.run(_your_ip_address_, port=5200, debug=True)

With this, others will be able to see your server (on the same network) and you will be able to make changes to your code and dynamically update your code without stopping and starting the server.

Step 4: Let's make a route

In our final step, we're going to implement something interesting (well sort of anyway). Let's say we have an application which will respond to /status by returning the following json:

INGREDIENT A: Some JSON response spec

{
    "appname": "My awesome app",
    "version": "0.1",
    "creator": "BigBird007"
}

Because Python dictionaries are very similar to JSON objects, we can specify the above JSON like this in Python:

data = {
    "appname": "My awesome app",
    "version": "0.1",
    "creator": "BigBird007"
}

To convert this Python dictionary to JSON so we can return it over the wire, we use the json library. The two methods you should just remember are json.dumps(a_python_object) and json.loads(a_json_string) ... these two methods allow you to go back and forth from Python to a JSON string (dumps) and from a JSON object (as a string) back to a Python object (loads).

INGREDIENT B: A /status route and handler

The syntax for specifying a route is

@app.route("your/route/here")
def the_handler_for_the_route():
    # your awesome implementation here

    # return some cool JSON usually ... 
    return

This pattern will be used over and over in your code, study it and remember it. To learn how to use this pattern to specify things like your GET or POST handlers, read the docs further here: http://flask.pocoo.org/docs/0.11/api/#flask.Flask.route and here: http://flask.pocoo.org/docs/0.11/api/#url-route-registrations. Everything you'd want to know will be there (including handling variable parts of your route, defaults, method handling, etc.).

Let's finish off our /status route ... make sure you place the route somewhere before the if __name__ ... line of code:

@app.route("/status")
def status_endpoint():
    data = {
        "appname": "My awesome app",
        "version": "0.1",
        "creator": "BigBird007"
    }
    return json.dumps(data)

Your final code should look like something like the sample file provided in app.py.