Hello Tiny Flask App

How to make the simplest of Python web applications.
This article is part of a sequence:
Introduction to Simple Web Applications with Flask
A series on learning how to make simple, one-file Flask apps.

Summary

This is a very tiny introduction to web application development using the Flask Python “microframework”. A web application is by no means the only, nor the best means of digital publishing. But knowing how to build one can help you think in more data-centric ways, while also forcing you to think about user interfaces and experiences.

In this tutorial, we just get acquainted with the basic conventions of Flask and web application development. This tutorial assumes you know a bit about Python, but virtually nothing else about the web stack, including what HTML or a web server is.

Objectives

  • Get introduced to the Python Flask web application framework.
  • Build a Flask app that will respond with a simple message when visited by a web browser.
  • Learn how to develop a Flask app, including how to run a local webserver.
  • Learn how to debug a Flask app.
Table of contents

Installing Flask

If you are running Anaconda, you shouldn't have to install Flask via pip. But just in case you don't, run this from your shell:

pip install Flask

As with any other library, if it's already installed, you won't break anything (hopefully).

Getting a proper text editor

You're going to want to do this with a proper text editor, such as Sublime Text 3 (do not download Sublime Text 2), which comes with a 30-day free period and an occasional (ignorable) reminder afterwards. Or, you could go with Github's free Atom editor.

In this tutorial, we'll be making a one-page web app. If you peruse other Flask apps, such as NICAR's First News App tutorial, you'll see that a web app consists of several files and folders. But right now, we'll just keep things simple with a single file named app.py.

Here's what the code for the finished web app will look like in your text editor:

image hello-world-sublime-project.png

There's a lot of conventions and structures you probably don't know. So try to find and focus on what you do know. Even if it's just this:

    "Hello world!"

Learning from the official documentation

The Flask documentation is great; there's even a Quickstart section titled, A Minimal Application. Our tiny Flask app basically follows its lead, with a few modifications that you should be able to understand and tweak yourself.

Dealing with errors

Web application development is a complicated business, and you will struggle with not just avoiding typical Python programming errors, but also, web application-specific errors. The hardest part, of course, is knowing the difference when you don't know much about Python and virtually nothing about web applications.

My intent is that you can complete the first parts of this tutorial without too much confusion…but I can't predict all the ways you might accidentally break things. So you might have to skip down to the Debugging section at the end of this tutorial if you hit a roadblock.

Creating app.py

Let's get started.

The core of a Flask application is a file named app.py; think of it as short for, application.

In your text-editor, create a new file named app.py – and keep track of where you save it, because you will need to be able to activate it from the command-line like so:

    python app.py

We'll get to that python-script-running step in a minute. First, we have to write the code for our app.

Importing the Flask library

As with all functionality that goes beyond Python's standard library, we need an import statement to bring in Flask. Add this to the top of app.py:

from flask import Flask

Instantiate

Then, instantiate a Flask object (technically, a flask.app.Flask object) and assign it to an easy-to-remember variable; people seem to go for the simple label of: app:

app = Flask(__name__)

Don't worry about that __name__ object, it's just a convention.

Finally, add this:

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

The above snippet is yet another common Python convention, one that you can get by with just memorizing rather than fully understanding…though at some point, if you're curious:

First try at app.py

All together, this is what your app.py file should look like:

from flask import Flask
app = Flask(__name__)

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

Save the file. Then jump into your command-line and change into the directory that app.py exists.

Running a Flask app

Running your Flask app is no different than running any other Python script. Go to your system shell and run:

python app.py

But unlike your typical Python script, this script, thanks to the Flask library, will start a local webserver. You should see this message (I'll frequently refer to it as a console message):

 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Here's an animated version of the process:

What does that mean? It means if you visit that URL in your web browser (127.0.0.1 always refers to your own machine), you'll see your brand new web app!

Your first (likely) accidental error

You might have made an error even before you tried visiting your web app with your browser. Here's a common error after running python app.py:

python: can't open file 'app.py': [Errno 2] No such file or directory

That error message means exactly what it says: you're trying to run a file named app.py but it doesn't exist. Which means you either didn't save the file properly. Or you didn't save it with the name app.py. Or you didn't save it to directory you thought you did. Or, when opening your Terminal and trying to navigate to where you think app.py exists…you didn't navigate to where you had hoped to be.

Use the standard shell commands to make sure you know where you are (pwd for Linux/OSX, or the Windows equivalent). And as much as possible use the Tab key to autocomplete, even for something as short as app.py.

Your first Flask web application error

Assuming you've followed my example exactly and haven't made a typo, pop open a new browser window and visit the URL at http://127.0.0.1:5000/.

Or, you might prefer the human-readable equivalent: localhost:5000).

Either one will result in a Not Found error message (aka, the dreaded 404) being displayed in your web browser:

image 404-localhost.png

Note: you may get an error message that reads, " Internal Server Error"

You can jump down to the debugging section for a few more details. Or, you can modify your call to app.run():

if __name__ == '__main__':
    app.run(debug=True)

This will allow the app to display a proper Python error message, so you can fix the typo/syntax error.

Tell the webserver to quit with Ctrl-C

Assuming you're at the point where your browser displays the Not Found error…well, your app is broken, and you need to fix it.

Time to abort. Hit Ctrl-C to break out of this unwanted sequence (this, or any other system process):

Note how visiting your web app at 127.0.0.1:5000 resulted in a couple of server messages:

127.0.0.1 - - [04/Apr/2016 18:34:53] "GET / HTTP/1.1" 404 -
127.0.0.1 - - [04/Apr/2016 18:34:53] "GET /favicon.ico HTTP/1.1" 404 -

You're basically a system devops watching traffic hit your webserver…in this case, you're seeing the error messages (note the 404).

Routing and views

So why did our web app return a 404 page? Because our app literally has no "pages" – you saw the 4 lines of code we've produced so far.

Part of what makes a web app a web app is that it has multiple paths, i.e. URLs. When you visit http://www.nytimes.com/ – i.e. its homepage – the NYT webserver is directing you to what's commonly known as an index page. When you visit the URL http://www.nytimes.com/pages/world, the pages/world path let's the webserver know that we want to be sent to wherever the World news section is on the NYT's great big webserver in the sky.

Right now, our web app doesn't include the code that defines even the most basic route, http://127.0.0.0.1/` – which is commonly referred to as the index page or homepage.

Without a single route defined, visiting 127.0.0.1:5000 causes the app to respond…with a "WTF I don't know who you are or what you want".

Creating a "homepage" route

To specify a route in our web app, we need to do two things:

  1. Define the path that leads to the route. This is a string, e.g. "/" and "/photos/cats, that follows the domain address in the URL, e.g. http://127.0.0.1/ and http://127.0.0.1/photos/cats
  2. Specify the view function that serves up the content at that route

Defining the path string

To define a path, use this convention (the @ sign is very important here) with the app.route() method:

@app.route("/")

Ignore the @ convention for now (technically, it's called a decorator) and instead, pay attention to the argument we pass to its route() method: "/". It's the / for the web domain URI at http://127.0.0.1/. It's simply the path, known as "/"

Creating the view function that serves a message

The decorator function @app.route() will "decorate" the view function that comes after it: the function that generates a message to be send to and rendered by the browser, i.e. the content that the user sees in their browser when they visit 127.0.0.1/.

We refer to this message-making function as the view function for the route that preceded it, e.g. /

Does it have to be HTML? Nope. Go for the classic message:

@app.route("/")
def homepage():
    return "Hello world!"

One thing to note: it doesn't matter what you name the view function (though obviously, name it something that makes sense to you on subsequent re-readings):

@app.route("/")
def booyahshaka():
    return "Hello world!"
@app.route("/")
def homepage():
    return "Hello world!"

A second try at running app.py

This is what the entirety of app.py should look like:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def whatever_homepage_blah():
    return "Hello world!"

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

Switch to your command-line and restart the server with:

python app.py

Then revisit http://127.0.0.1:5000/

Joy:

image 200-hello-world.png

If you check the Terminal window for wherever you ran python app.py (i.e. the console window), each visit/reload of your webserver should trigger a new set of server messages:

A quick note about terminology and ports: The 5000 refers to the port number on your computer, not a part of the webserver path. By default, a Flask app will run a web server on your computer at port 5000 for testing. Why 5000? Because it's not usually taken up by other apps currently running on your system…

Efficiently iterating on our simple app.py

Our Flask app is very basic, but it's never too early to learn some good habits for app development, one line at a time.

First, let's change the message that the view function returns for the "/" route. Don't shut down your app; just switch over to your editor and make a change to app.py. Make it return a multi-line string (denoted with triple quotation marks, """) just for kicks.

And by now, you should be comfortable with the fact that the name of the view function can be completely arbitrary:

@app.route("/")
def supercalifragalistic():
    return """Hello 
    and 
    goodbye world!
???    """

Please return something

A segue: note that the view function must return a value. Your print() function has no power here, so don't do this:

@app.route("/")
def supercalifragalistic():
    print("""Hello 
    and 
    goodbye world!
???    """)

Add auto-reload to the app configuration

If you reload your browser at 127.0.0.1:5000/, you should see that nothing has changed. By default, a currently-running Flask app won't render changes made to its source code. You have to shut down the app's web server down with Ctrl-C, then restart it with python app.py.

And then reload the browser.

As with all things inconvenient, the Flask library maintainers have come up with a way to streamline the reloading process. has come up with a way to streamline reloading for development purposes.

In the call to the app.run() method, pass in the keyword argument, use_reloader=True:

if __name__ == '__main__':
    app.run(use_reloader=True)

Shut your app's web server down and restart it. Any changes you make to app.py should be reflected upon reloading the browser.

Debugging a Flask app in development

Web apps are fun. But with their browser-friendly interface comes the price of a new layer of things to debug. When your app does something weird, is it the browser's fault? Is it in the HTML/JS/CSS code that you hacked together? Or is it a Python error?

Hint: early on, most of your errors are going to be good-ol fashioned Python errors. With your app and web server still running, make an intentional error. For example, alter your view function to return something that is obviously an error, e.g.

"Hello" + 1

In context, with the rest of app.py:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def homepage():
    return "Hello" + 1

if __name__ == '__main__':
    app.run(use_reloader=True)

When reloading the page, you should get this completely opaque error message in the browser:

Internal Server Error

The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.

image 500-internal-error.png

Enabling debug mode

That vagueness of error message is actually a good thing. When your app is live and facing the entire world and unexpectedly breaks, you don't want everyone in the world to know exactly which line in which file threw what type of error exactly.

But such obfuscation is fatal during development – you don't want to be spending hours guessing where you made a typo. You need the typical error reporting that Python provides, especially as you stumble your way in this new development framework.

Having the Flask app display a proper error message in the web browser is as easy as supplying a keyword argument to the app's run() function:

debug=true

In context:

if __name__ == '__main__':
    app.run(debug=True, use_reloader=True)

Ah…sweet, verbose stack trace:

image 500-internal-error-stacktrace.png

Note that the relevant message is at the top:

TypeError: Can't convert 'int' object to str implicitly

You can read more about Flask's debug mode in its documentation.

Using print() to print messages to the console

While print() functions won't ever impact what's rendered by the browser, they still will print out to the console screen – i.e. the Terminal window in which you ran python app.py.

There's obviously better, more sophisticated ways to do error logging built into the Flask library…but in a jiffy, go with what works: use print() calls to tell you what's going on in your app, as you would in any Python script:

from flask import Flask
app = Flask(__name__)
print("initiated the app! With a name of:", __name__)

@app.route('/')
def homepage():
    print("Hey I'm visiting the homepage!")
    return "Hello world!"

if __name__ == '__main__':
    print("App is starting...I think?")
    app.run(use_reloader=True)
    print("Umm...no idea what/how this message will be seen...")

Here's what my server console looks like when I start the app, visit the homepage, and then shut the app down with Ctrl-C:

Other run-time application errors

Beyond Python syntax and logic errors, there are going to be a myriad of errors exclusively in the domain of running a web application. I'll cover a few of the show-stoppers that you are likely to run into, even with just a "Hello world" app:

Connection refused/"This site can’t be reached"

In Chrome, this error looks like this:

image connection-refused.png

This could mean either of these things:

  1. You mistyped the URL port number, e.g. localhost:5999 instead of localhost:5000
  2. You correctly typed the URL and port number but your web server isn't running, i.e. you forgot to execute python app.py

OSError: [Errno 48] Address already in use

So you're switching between multiple browser and Terminal windows like a pro, but as soon as you try to execute python app.py, you get this error:

OSError: [Errno 48] Address already in use

This error means that in one of your other Terminal windows, you've already run a web app (Flask, or even something else) that is hogging up port 5000. You need to shut it down and free up the port 5000 if you want to run python app.py.

404 Not Found (again)

Don't forget that classic "Not Found" error. Just because we fixed one instance earlier in the lesson doesn't mean that the web server knows how to deal with all the typos you might throw its way. Instead of visiting a path that you've written a route function for – i.e. / – try visiting a made-up path, e.g.

    http://127.0.0.1:5000/hey/heyhey

Because that path was never defined in app.py, you'll get the 404:

image 404-heyhey.png

Basically, not only do you have to worry about typos in your Python code, but typos in your browser bar, too.

Conclusion

And that's a Flask app. While we haven't done much of what normally constitutes web application development, it's important to get a feel for the bare foundation of a Flask app and what we get with a few lines of boilerplate code.

Here's all the code for the app we created, though your function/variable names may vary. See how much of it you can reproduce from memory:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def homepage():
    return """
    Hello world!
    This is my first web app!
    """

if __name__ == '__main__':
    app.run(use_reloader=True)

In the next lesson, we'll create an app that serves up a "proper" webpage with actual HTML. But it's important to understand that the app's view function really just returns a string object – and thus, a "proper" webpage with "real" HTML is just a big string.

This article is part of a sequence:
Introduction to Simple Web Applications with Flask
A series on learning how to make simple, one-file Flask apps.