Lab 8: Introduction to
Web Applications
Web Applications
Part 1: Intro to Flask
If you find typos or problems with the lab instructions, please let us know.
Note: Parts 1 and 2 of this lab are individual work. Each of you should do it separately, though you are most welcome (and, in fact, highly encouraged) to help one another if/when you are stuck.
Setting Up Your Repo
Each partner will create a separate repo for this part, and then you and your partner will work together in a new repo for the rest of this lab. Although Lab 8 doesn't have starter code, we do have a repository template that provides the basic infrastructure needed to work in GitHub Codespaces.
Here are the full instructions:
Go to the "Repositories" tab in the SPIS 2023 GitHub organization by clicking here: https://github.com/orgs/ucsd-cse-spis-2023/repositories
Click "New Repository"
Underneath "Repository template" select the dropdown (that currently says "No template") and choose ucsd-cse-spis-2023/flask-template instead.
In the "Repository name" text box, enter spis23-lab08-Name, where name is your preferred first name and last initial (for instance, spis23-lab08-Rhea-B).
Be sure that "Private" is checked (not "Public")
You do not check the "Add a README file" box -- you'll already get a placeholder README file from the template.
Click the "Create repository" box at the bottom-right and wait a minute or so for the setup to complete.
Working with GitHub Codespaces
At this point, we've outgrown what we can do in Colab notebooks, so now we need to switch to a full-fledged development environment. We can do this entirely within GitHub by using Codespaces, a cloud-based development environment that lives on a virtual machine and runs entirely within your web browser. We will interact with the Codespaces by using the VS Code editor in the browser.
To start a new Codespace, go to the main page for your GitHub repo, and click on the Green "<> Code" button in the upper right corner. Click on the "Codespaces" tab if neccessary, and then click on the big green "Create codespace on main" button. Then wait a little bit for the Codespace to start.
The next time you work on your project, you won't need to create a new Codespace because you can resume using the previous one. Click on the green "<> Code" button in the upper right. You'll see your codespace listed by name now; click on the name of your Codespace to get started. For example, my codespace was randomly assigned the name Fuzzy Sniffle:
If you close your tab, or leave the Codespace alone for too long, it will automatically stop, but can always be started up again.
Step 1: A basic Hello World webapp using Flask
Flask is a Python module/framework that provides an easy way to get started with web programming.
The easiest way to get started is to try some small examples. Below is a small example of a Python program that uses Flask. There are seven lines of code here (not including the blank lines), and before the end of this document, we’ll explain every single part of every one of these lines.
This web application isn't very interesting — it puts the words “Hello World!” up in the browser every time you send it a request. But it provides a starting point, from which we can begin to do more interesting things.
To create the simple web app, do this:
Open up Codespaces for your solo repo
You should see the file Explorer on the left. If not, click on the icon on the far left bar with two overlapping sheets of paper. Right-click in the blank space of the Explorer bar and select "New File...". Name your file main.py
In the main.py file, type these lines of code:
(You are encouraged to type them in rather than just copying/pasting; that will get the code in your head a bit more.
But, if you want to copy/paste, it's fine; we can't and won't check up on you there.)
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run(host='0.0.0.0')
Note that sometimes, depending on browsers, platform, etc., if you copy/paste you may get extra blank lines between your code, i.e. something that looks like the image on the left below nstead of the image on the right. In that case, please take the time to remove the extra blank lines.
Though we won't mention it again, we'd really like you to remove the blank lines any time they pop up in copy/pasted code.
❌ Copy / Pasted, with extra blank lines
(This is what we would prefer not to see)
(This is what we would prefer not to see)
✅ Typed, or copy/pasted then cleaned up.
This is what we would prefer to see.
This is what we would prefer to see.
Now run the code, and you'll have a web app running!
To get this working, all you have to do is click the play button in the upper right corner. If you mouseover this button, it will say Run Python File.
Here is what the output in the terminal should look like (there'll probably be some extra output as well, but these lines are the most important):
* Running on http://127.0.0.1:5000/
...
(Press CTRL+C to quit)
If that works, great! This may not be very impressive, but it gets a little more awesome when you realize that you’ve just put up a local web server that you can connect to with a browser! A new browser tab or window should open automatically in your web browser for you to see this -- you should see the message “Hello World” come up in the browser.
Now: check in with your partner and verify that both of you were able to get a simple hello world app running before moving on.
Step 2: Play around with it
If you can, you should arrange your windows so that you can see both the Codespaces tab with your editor and the browser tab with "Hello World!" side by side in separate windows.
Now, here are a few things to try, and some questions to answer. As you try these things and think through what is happening, you should begin to understand a few things about how this code is working:
(1) In the browser window where you see "Hello World!", click the refresh button.
What do you see happen in the Terminal portion in the lower-right of the Codespaces VS Code window each time you click the button?
NOTE: If you look in the address bar of the browser tab with "Hello World" you'll see an address like
https://fuzzy-sniffle-rp6469g69643x7r5-5000.app.github.dev/
This URL can be accessed from another device, but you will have to log in to GitHub first.
(3) Click inside the Terminal portion of your VS Code window (in the lower right) and then press either Ctrl-C or Cmd-C to stop the web server.
Once it's stopped, try refreshing the page in the regular browser.
Does the page load?
And what (if anything) happens in the Terminal window?
Step 3: Understanding all the lines of code
Ok, here is an explanation of each of the lines of code. Then, we’ll walk through how to do a few things that are a bit more interesting.
1) from flask import Flask
This code pulls in the definition of a new datatype called Flask (note the uppercase F) from a module called flask (note the lowercase f.) In Python, when you import something, you are telling the Python interpreter that you want to build your software on top of some software already written by someone else.
2) app = Flask(__name__)
This line of code is an assignment statement. The right hand side is evaluated, and then the variable on the left is set to the result of the right hand side. The right hand side, Flask(__name__), creates a new object of type Flask. The __name__ parameter is explained further in the box “About the First Parameter” on this page of the api documentation. We’ll defer the details for now, and just say: for very simple Flask applications, __name__ is always the correct choice.
3) @app.route("/")
The @ signals that what follows is a Python annotation. It indicates that there is some special way the following function definition should be handled. In this case, the annotation app.route("/") indicates that this function is called whenever we ask for the main page on this web server (i.e. "/". This will make more sense when we add other pages later.
4) def hello():
5) return "Hello World!"
Lines 4 and 5 are a regular plain old Python function definition. We can see that the function is called hello, and takes no parameters. This function returns a string, "Hello World!", which is used as the page to display for the main page of the web server ("/").
6) if __name__ == "__main__":
Line 6 has an if test that checks the special variable __name__ to see if it has the special value __main__. This is the mysterious “conditional script stanza”, which we aren’t going to explain in detail here (though if you are curious, here's an explanation).
Instead, we’ll just say that whatever “main thing” a Python code is supposed to do when you type python3 main.py, in this case python3 main.py should typically be wrapped in this if test. That makes your file much more useful, because then the definitions it contains can be included as a module in another file.
7) app.run(host='0.0.0.0')
Line 7 is the line that actually causes our web server to start running. The dot-notation app.run(host='0.0.0.0') tells us that run is a method of the object app. By putting () after it, we are making a function call to that method, and starting things in motion. The host='0.0.0.0' is just a placeholder that tells Flask to listen for web requests on any internal IP address.
GitHub's Codespaces does some magic so that our web requests to load our site on the domains like https://fuzzy-sniffle-rp6469g69643x7r5-5000.app.github.dev/ will actually be relayed through the virutal machine containing our Codespace so that Flask sees the web requests as coming from the machine it's running on. That's why you see Running on http://127.0.0.1:5000 in the terminal ouput above: 127.0.0.1 is not a "real" IP address but rather a placeholder that stands for "this same machine." And 5000 is the port that our application is running on. We typically pick a special port to run our development servers on; in the real world it's common for a single server (or virtual server) to be running several different development servers at the same time, so we want to pick an arbitrary port for every development server.
It's also possible to directly specify the localhost by writing app.run(host='127.0.0.1') instead.
Step 4: Recording your Work
Now it's time to commit your work before moving on to Part 2. Before we give those instructions, it's important to understand a few things about how Git and GitHub work in relation to your Codespace:
Your Codespace is a virtual machine that contains a clone of your Git repository on its local filesystem. Git is very different than, say, Dropbox or OneDrive: there is no automatic syncing of your work to the GitHub repo. Therefore, as you work in the VS Code editor in your Codespace, you may have noticed that when you save a file nothing happens to your repo on GitHub.
The files inside your local clone of your repository are managed by Git. But you need to explicity create a commit in Git to tell Git to store a new version of your files in your repo. This does not happen automatically. You will save your files frequently, but will create Git commits when you've reached a small milestone: you've finished a part of a lab, fixed a tiny bug, added a new file, made a small bit of progress on a feature, etc. We'll show you how to do this below.
None of the commits you create in your local clone of your repo are automatically synced back to GitHub, and no one else's changes to your GitHub repo are automatically synced to your local clone. You must do this explicitly by pushing (sending new commits from your local clone back to GitHub to be integrated into your repository) and pulling (getting new commits from the GtiHub repo). We'll show you how to do this below.
You must always pull before you push. If there are commits in the GitHub repo (i.e. from your partner) that you do not have in your local clone, then your push will be rejected until you pull these new commits. Git will try to merge these commits automatically, but sometimes you have to get involved. If this happens, ask a Mentor for help.
Your Codespaces will remain around for two weeks after they've been stopped (i.e. longer than you'll be working on this lab), so that you won't lose any uncommitted or unpushed work. Be careful before you delete a codespace that you do not have any uncommitted or unpushed work on that Codespace. Once a Codespace is deleted, any work that hasn't been pushed to your GitHub repo will be lost forever.
How to commit and push in VS Code
In the left sidebar, click on the Source Control icon (it looks like three circles connected by a few lines). You should see something like the image on the right.
Under "Changes," you should see a list of the files you've worked on so far. The letter on the far right corresponds to whether the file is untracked and not yet known to Git ("U") or whether it has been modified since the last commit ("M"). Click on the "+" in each row for each file you want to add to your commit (right now this should just be main.py). This will stage the file to be included in the next commit.
Each commit must contain a message, so type a message such as "Finished lab 08 part 1" in the Message box. Then click Commit to finish creating the commit.
The blue button you just clicked should now read "Sync Changes 1" where 1 is the number of commits in your local clone that have not yet been pushed to GitHub. Click the button again to push.
Next, let's create a branch in Git to keep track of our progress after each part of the lab (so the mentors have an easier time giving feedback).
In the Source Control sidebar, click the "..." in the upper right to open a menu. Click "Branch" -> "Create Branch ...".
In the box that appears enter "part1" as your branch name.
Click the blue "Publish Branch" button in the Source Control sidebar.
There may be a pop-up in the lower right corner of a screen that asks if you want to create a pull request. Click the button to dismiss the pop-up -- you don't need this.
Now we want to switch back to working on the main branch. Click the "..." again, and then select "Checkout to..." from the menu. Another selection should appear at the top of the screen. Choose "main" (not "origin/main") to switch back to working on the main branch.
That's it for Part 1! Ok, what's next?
Next, we'll try to make an app that can actually run some code instead of just printing Hello.
That's in Part 2. which you may start now!