<style>
.reveal {
font-size: 27px;
}
.reveal div.para {
text-align: left;
}
.reveal ul {
display: block;
}
.reveal ol {
display: block;
}
img[alt=drawing] { width: 200px; }
</style>
# COMP1010
## 5 Web Application Development
### 5.3 Web Servers and Flask
---
## Recap
* Previously on COMP1010:
* 5.0 Overview: we discussed the role of web browsers and web servers in running a web application.
* 5.1 HTML: we learnt how to write HTML to create a web page.
* 5.2 PyHTML: we learnt how to create HTML quickly and accurately using PyHTML.
* But:
* Our forms don't do anything.
* We can't go from one web page to another.
---
## Warning - It Might Seem Like a Lot
* This lecture looks like it has a lot of information.
* It might seem overwhelming at first.
<br>
### BUT...
* After this lecture, you will be able to copy-paste generic Flask server code and (because you understand what each line means) make the appropriate changes to make your application run.
* So don't worry about being able to write any of this from scratch. Just understand what it does so you can adapt it to your own project.
---
## Generic Flask Application Code
```{python}
from flask import Flask, request
from pyhtml import html # TODO add imports
app = Flask(__name__)
@app.route('/', methods=["GET", "POST"])
def homepage():
if request.method == 'POST':
# TODO you received form data, handle it
# (usually produce HTML)
else:
# TODO you didn't receive form data
# (usually produce HTML)
response = html(
# TODO put your pyhtml code here
)
return str(response)
if __name__ == "__main__":
app.run(debug=True)
```
---
## Your Goal
* Your goal in this lecture, is to learn to understand the different parts of this code so that you can copy and paste it and then:
* insert your own code instead of the TODOs (mostly pyhtml to produce the content specific to your application)
* add more routes and functions (by copying the one already there and adjusting it to work for your application)
---
## Let's start from the beginning...
---
## Flask: A Simplest Application
```{python}
from flask import Flask
app = Flask(__name__)
@app.route('/')
def homepage():
return "Hello World!"
if __name__ == "__main__":
app.run(debug=True)
```
---
## Understanding the Application
### Things we already know:
* Checking if this file is the one to run before doing anything: (covered in topic 4)
```{python}
if __name__ == "__main__":
```
* A function which returns "Hello World!" (Which can be interpretted as a very simple web page) (covered in topic 3.2.5)
```{python}
def homepage():
return "Hello World!"
```
---
## Understanding the Application
### New things:
* importing Flask (still quite familiar)
```{python}
from flask import Flask
```
* creating a Flask object
```{python}
app = Flask(__name__)
```
* running the Flask object
```{python}
app.run(debug=True)
```
These allow us to use the Flask framework to do a lot of "behind the scenes" work.
---
## Understanding the Application: Routes
* To fully understand the line `@app.route('/')` we need to add a few more **routes**.
* Each route is associated with a function. (It needs be to created in the line above the function it is associated with.)
```{python}
from flask import Flask
app = Flask(__name__)
@app.route('/')
def homepage():
return "Hello World!"
@app.route('/another_route')
def some_other_function():
return "This is the webpage associated "+ \
"with <code>another_route</code>."
@app.route('/list_desserts')
def desserts():
return "Cake, Popcorn, Brownies"
if __name__ == "__main__":
app.run(debug=True)
```
---
## Flask: A Simplest Application
* Now have a read through the code and check you understand each step
```{python}
# import Flask
from flask import Flask
# create the Flask app
app = Flask(__name__)
# declare a route and link it to a function
@app.route('/')
def homepage():
# return HTML from the function --> this will show up when that route is navigated to
return "Hello World!"
# if this file has been run, then run the Flask app
if __name__ == "__main__":
app.run(debug=True)
```
---
## Note: Simplest Application
* The examples above produce very simple HTML.
* I've done this because I want you to get familiar with the Flask elements without being overwhelmed by PyHTML.
* So let's take some time to write a more complex one.
---
## Simple Calculator: Flask App
* Write a Flask application with a two web pages:
* The first page should get the information from the user:
* Ask the user to enter 2 numbers and a symbol. For example `3 + 4` or `7 * 8`.
* The second page should display the result of the calculation.
---
## HTTP Request Methods
* Now that we know how to create different web pages under different routes, we need to be able to move from one page to the next.
* Hypertext Transfer Protocol (HTTP) is designed to enable communications between clients and servers.
* A client (browser) sends an HTTP request to the server; then the server returns a response to the client. The response contains status information about the request and may also contain the requested content.
* The two most common HTTP Methods:
* GET
* POST
---
## HTTP Request Methods: GET and POST
* GET:
* Is used to request data.
* Should not be used when dealing with sensitive data.
* So far we have used GET requests (they are the default when HTTP methods aren't specified for a route) to sent a request (the url) to the server and return the HTML to display.
* POST:
* Is used to send data to a server to create/update a resource.
* An example of such data is the contents of a form which has been submitted.
* The data sent to the server with POST is stored in the request body of the HTTP request.
---
## Getting to the Next Webpage
### Step 1: Tell the form where to go.
* Forms:
```{python}
form(action="destination_route")(
# Other form elements
input_(type="submit", value="Go")
)
```
* In the code above, when the `submit` is clicked, it will go to the `destination_route` function.
---
## Getting to the Next Webpage
### Step 2: Check that the destination route can handle POST requests.
* The default request is GET, so until now we haven't had to specify anything to get a web page.
* When a function is executed as a result of a form being submitted, it needs to specify that it is able to receive POST requests.
---
* To enable only GET:
```{python}
@app.route('/destination_route')
```
Or
```{python}
@app.route('/destination_route', methods=["GET"])
```
* To enable both GET and POST:
```{python}
@app.route('/destination_route', methods=["GET", "POST"])
```
* To enable only POST:
```{python}
@app.route('/destination_route', methods=["POST"])
```
---
* Now update your Simple Calculator application so that the user can press "Calculate" and be taken to the next web page displaying the result.
---
## Getting to the Next Webpage
### Step 3: Extract the data from the HTTP request in the destination.
* Now when we go to the game page, we need to be able to find out which numbers and symbols the user entered.
* Calculate the result.
* And send the updated HTML.
<br>
### How do we do this?
---
## Getting to the Next Webpage
### Step 3: Extract the data from the HTTP request in the destination.
* Import request from Flask library.
```{python}
from flask import Flask, request
```
* If we accept both GET and POST requests, we need to check if it was a POST (before we try and access the contents of the form).
```{python}
if request.method == 'POST':
```
* Then we can access the details of what was in the form. For this, we need to know the `name` field of our form element.
```{python}
my_variable = request.form['field_name']
```
---
## HTTP Responses
* When we return HTML from our server, it's referred to as the HTTP response.
* Flask also includes some information in it for the web browser.
* HTTP status codes:
* 2XX: Success (usually 200, meaning OK)
* 4XX: Client Errors (often 404, meaning Not Found)
* 5XX: Server Errors
* A full list of HTTP status codes can be found [here](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)
---
## Limitations So Far
---
## Keeping Track of Data Within the Server
* Hidden field (not secure from being seen and changed by the user)
* Global variable (prevents our program from being stateless - more likely to have bugs in our code)
* Cookies (great. We will learn this next. But not secure. Can be removed by the user by clearing cookies.)
* File on our server (not great for speed with large data, otherwise good, will be covered in this course)
* Database (good. not covered in this course.)
* We also won't be covering security such as encryption in this course.
---
## Keeping Track of Data Within the Server
| | Hidden Fields | Global Variables | Cookies | File on Server | Database |
|---|:-:|:-:|:-:|:-:|:-:|
Viewable by user | Y | | | | |
Changeable by user | Y | | | | |
Deletable by user | Y | | Y | | |
Makes code more likely to have bugs (mistakes) | | Y |
Expire | | | Y |
Ease of implementation | Very Easy | Very Easy | Easy | Easy | Hard |
Will be taught in COMP1010 | | | Y | Y |
---
## References
* If you're interested in learning more and taking these skills further:
* [Flask Quick Start Tutorial](https://flask.palletsprojects.com/en/2.0.x/quickstart/)
* [Flask Tutorial](https://flask.palletsprojects.com/en/2.0.x/tutorial/)
* [More about different types of HTTP requests](https://www.w3schools.com/tags/ref_httpmethods.asp)
* [Someone else's articulation of why I believe global variables are evil. (And incidentally, an example of what can go wrong when producing HTML which using PyHTML would not allow to happen.)](http://swcarpentry.github.io/training-course/2012/11/claiming-a-topic-why-global-variables-are-a-bad-idea/)
---
{"metaMigratedAt":"2023-06-16T20:56:30.992Z","metaMigratedFrom":"YAML","title":"5.3 Web Apps Servers and Flask","breaks":true,"slideOptions":"{\"transition\":\"slide\"}","contributors":"[{\"id\":\"969c3c3d-0ef4-4f08-b22a-2f2b8951224b\",\"add\":12212,\"del\":2056}]"}