Install requirements (ideally in a virtual env)
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install -r requirements.txt
Run example app
$ python app.py
-
Client/server dichotomy
-
Client sends a http request to server, server sends a http response to the client
-
Several HTTP methods, most common are:
- GET - for retrieving data
- POST - for submitting data
-
When visiting a website, your browser is sending a GET request and recieving a response (with HTML)
-
Send HTTP requests from command-line with
curl
- e.g.
$ curl https://www.google.ca
$ curl --help
for more info$ tldr curl
- e.g.
-
python
requests
library
import requests
requests.get('https://www.google.ca')
-
can send text/HTML, json, JS, CSS, and more!
-
Common to request data in JSON format from API endpoints (or routes)
$ curl https://jsonplaceholder.typicode.com/posts
import requests
response = requests.get('https://jsonplaceholder.typicode.com/posts')
posts = response.json()
- Note: your browser can also fetch and display JSON
- Server = computer listening for HTTP requests
- Flask is a Python module that abstracts away a lot of boiler plate
from flask import Flask
app = Flask(__app__)
@app.route('/')
def index():
return 'Hello, world!'
$ flask run
will look for file namedapp.py
- Change default by setting
FLASK_APP
env variable - Run in debug mode by setting
FLASK_ENV=development
(restarts server when you make changes) - Alternativley, to run with
$ python app.py
if __name__ == '__main__':
app.run(debug=True)
$ curl http://localhost:5000
(look at server logs)
@app.route('/submit', methods=['POST'])
def submit():
return 'Only post allowed!'
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success
- 200s = success
- 300s = redirect
- 400s = bad request
- 403 = forbidden
- 404 = not found
- 500s = server error
- Flask auto adds error page for you
$ curl http://localhost:5000/another-route
- Can customize error handling: https://flask.palletsprojects.com/en/1.1.x/errorhandling/
@app.errorhandler(Exception)
def handle_bad_request(e):
return 'Bad request', 400
@app.route('/hello/<name>', methods=['POST', 'GET'])
def hello_name(name):
return 'Hello {}'.format{name}
- can send data in GET requests in url with query-params (everything following ?)
https://ca.indeed.com/jobs?q=data+science&l=remote - accessible through Flask's
request
object
@app.route('/search', methods=['GET'])
def search():
args = request.args
print(args)
if 'q' not in args:
return 'Missing query', 400
return 'You searched for {}'.format(args['q'])
- Header fields: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
- Metadata for the request
- Can inspect in browser console
import requests
response = requests.get('https://google.com')
dir(response)
response.headers
response.content
- SM web app is SPA
- single page that is dynamically updated with different content
curl https://app.sharpestminds.com/mentor-bio/russell-pollari
Normally returns JS
but can listen for user agent and return cached version:
curl https://app.sharpestminds.com/mentor-bio/russell-pollari -A googlebot
-A is short for adding user-agent, could also do
curl -H 'User-Agent: googlebot' https://app.sharpestminds.com/mentor-bio/russell-pollari
@app.route('/submit-form', methods=['POST'])
def submit_form():
data = request.form
print(data)
if 'name' not in data:
return 'Missing name', 400
if 'email' not in data:
return 'Missing name', 400
return 'Your name is {}, your email is {}'.format(data['name'], data['email'])
curl -d "name=russell&email=russell@sharpestminds.com" http://localhost:5000/submit-form
@app.route('/submit-json', methods=['POST'])
def submit_json():
data = request.json
print(data)
if 'name' not in data:
return 'Missing name', 400
return jsonify({
'reversed_name': data['name'][::-1],
'other_data': 'blah blah blah'
}), 200
curl -d '{"name":"russell"}' -H 'Content-Type: application/json' http://localhost:5000/submit-json
-
HTML, header (title, scripts, tags)
-
body = what you see
-
elements
<p>, <a>, <table>
- attributes
class
id
href
- attributes
-
Flask lets you pass variables to html templates
@app.route('/hello/<name>', methods=['POST', 'GET'])
def hello_name(name):
return render_template('hello_name.html', name=name)
templates/hello_name.html
<html>
<body>
Hello, {{ name }}
</body>
<html>
<h3 style="color: green;">
- Or
<style>
tag in header
<style>
h3 { color: green; }
</style>
- can use class attribute instead of specific element
<h4 class="title" />
<style>
.title { color: red }
</style>
-
Inspect element and edit styles from browser
-
Most common to link to external stylesheet (usually as static asset)
/static/styles.css
<link rel="stylesheet" href="/static/styles.css">
- Can be hosted elsewhere. e.g. Bootstrap is good for getting pretty styles out the gate:
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
- e.g. style a button
<button class="btn btn-primary"> Submit </button>
- Browsers's have JS compilers
- "event" driven
- can manipulate HTML through DOM
<script>
function handleButtonClick() {
alert('You clicked a button!')
}
function handleNameChange(value) {
console.log(value);
document.getElementById("show-name").innerHTML = value;
}
</script>
<input id="name" oninput="handleNameChange(this.value)"></input>
<p id="show-name"></p>
<button class="btn btn-primary" onclick="handleButtonClick()">Submit</button>
- usually external script with src attribute
<script src="/static/script.js"></script>
<form action="/submit-form" method="POST">
<input name="name" />
<button>
Submit
</button>
</form>
- Fetch data from server without refreshing page
- AJAX https://www.w3schools.com/js/js_ajax_intro.asp
XMLHttpRequest
$.ajax
(jquery) https://api.jquery.com/jquery.ajax/- new API for Browsers
fetch
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
e.g. send a request to /submit-json and print the response in the console
fetch('/submit-json', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'name': 'Russell'
})
}).then(response => {
return response.json()
}).then(result => {
console.log(result);
});
- many browsers have different features (JS, HTML, CSS), can check availability per
browser
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API