Flask: Difference between revisions
From charlesreid1
| (22 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
=Basics= | =Basics= | ||
== | ==Basic App== | ||
Run a Flask app that is bound to all network interfaces on the host, and listens on port 5000: | |||
<pre> | |||
from flask import Flask | from flask import Flask | ||
| Line 22: | Line 14: | ||
return "Hello, World!" | return "Hello, World!" | ||
if __name__ == '__main__': | |||
app.run(host='0.0.0.0', port=5000, debug=True) | |||
</pre> | |||
If host and port are not specified, flask will only listen on the local network interface on port 5000. | |||
<pre> | |||
if __name__ == '__main__': | if __name__ == '__main__': | ||
app.run(debug=True) | app.run(debug=True) | ||
</ | </pre> | ||
==Routes== | |||
== | ===Simple hello world route=== | ||
A simple hello world route: | |||
< | <pre> | ||
from flask import Flask | |||
... | |||
@app.route('/hello') | |||
def hello(): | |||
return "Hello, World!" | |||
</pre> | |||
===Returning HTML=== | |||
To return HTML, we can return it in a string: | |||
<pre> | |||
from flask import Flask | |||
... | |||
@app.route('/get_html') | |||
def get_html(): | |||
return "<h2>Flask Returns HTML Code</h2>" | |||
</pre> | |||
===Returning JSON=== | |||
If we are writing an API, we want routes that return JSON. we can use Flask's jsonify function: | |||
<pre> | |||
from flask import Flask, jsonify | from flask import Flask, jsonify | ||
... | |||
@app.route('/list') | |||
def list(): | |||
d = {'a' : 1, 'b' : 2, 'c' : 3} | |||
return jsonify(d) | |||
</pre> | |||
{ | |||
===Rendering templates=== | |||
This example shows how to take an integer variable from the URL and use it on an HTML template page: | |||
<pre> | |||
from flask import Flask, render_template | |||
... | |||
@app.route('/sample/<int:sample_number>') | |||
def sample(sample_number): | |||
render_template('sample.html', sample_number=sample_number) | |||
</pre> | </pre> | ||
The contents of <code>sample.html</code> are given below: | |||
<pre> | |||
<html> | |||
<head> | |||
<title>Sample {{sample_number}}</title> | |||
</head> | |||
<body> | |||
<h2>{{sample_number}}</h2> | |||
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula.</p> | |||
</body> | |||
</html> | |||
</pre> | |||
===Raising errors=== | |||
To abort with a 400 (server error), use the abort function | |||
<pre> | <pre> | ||
from flask import Flask, abort | |||
... | |||
@app.route('/how_to_abort') | |||
def how_to_abort(): | |||
import random | |||
if random.random() < 0.5: | |||
abort(400) | |||
else: | |||
return "<h2>Hi there!</h2>" | |||
</pre> | </pre> | ||
===Exceptions and errors=== | |||
To write a custom exception that will return <code>abort(YYY)</code> (where YYY is an HTTP code), you can write an exception class that defines a status_code private variable: | |||
<pre> | <pre> | ||
class InvalidUsage(Exception): | |||
status_code = 400 | |||
def __init__(self, message, status_code=None, payload=None): | |||
Exception.__init__(self) | |||
self.message = message | |||
if status_code is not None: | |||
self.status_code = status_code | |||
self.payload = payload | |||
def to_dict(self): | |||
rv = dict(self.payload or ()) | |||
rv['message'] = self.message | |||
return rv | |||
</pre> | </pre> | ||
Next, we need to create a handler for this type of error, and register it with our application: | |||
<pre> | |||
from flask import jsonify | |||
... | |||
class InvalidUsage(Exception): | |||
... | |||
@app.errorhandler(InvalidUsage) | |||
def handle_invalid_usage(error): | |||
response = jsonify(error.to_dict()) | |||
response.status_code = error.status_code | |||
return response | |||
</pre> | |||
Described here in the flask documentation: http://flask.pocoo.org/docs/1.0/patterns/apierrors/ | |||
==POST Endpoints== | |||
To deal with data sent via a POST request, use the <code>request</code> variable, imported from Flask, and get the POSTed data using <code>request.json</code>: | |||
<pre> | <pre> | ||
from | from flask import Flask, jsonify, abort, request | ||
... | |||
@app.route('/post_something',methods=['POST']) | |||
def post_something(): | |||
if not request.json: | |||
abort(400) | |||
post_data = request.json | |||
# Now render a template for the user | |||
# and populate the template variables | |||
# with data that was POSTed | |||
render_template('posted.html', | |||
title = post_data.get('title','A Pretty Boring Title'), | |||
author = post_data.get('author','Anonymous Coward'), | |||
color = post_data.get('color','blue'), | |||
) | |||
# NOTE: | |||
# If you'd rather return json, just do | |||
# return jsonify({'status':'ok'}), 200 | |||
</pre> | </pre> | ||
Now we can POST data to the server by adding the JSON content type to a curl request, and pass data in using the -d flag. here's the curl request: | |||
<pre> | <pre> | ||
$ curl -i -H "Content-Type: application/json" -X POST -d '{"title":"My first post", "author":"Gladys Overwith", "color":"orange"}' http://localhost:5000/post_something | |||
</pre> | </pre> | ||
=Packaging Flask Apps= | |||
[[Flask/Packaging]] - a page that covers how to bundle flask apps into a ready-to-distribute Python package | |||
=Resources= | |||
==Flaskadillo== | |||
I put together a tutorial on how to use Flask. This is available in the flaskadillo repo: | |||
* https://git.charlesreid1.com/charlesreid1/flaskadillo | |||
* https://github.com/charlesreid1/flaskadillo | |||
==Links== | |||
The Flask mega tutorial is really handy: http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world | |||
Micro blog example: https://stormpath.com/blog/build-a-flask-app-in-30-minutes | |||
=Flags= | |||
[[Category:API]] | |||
[[Category:Python]] | |||
[[Category:Web]] | |||
[[Category:Web Server]] | |||
[[Category:REST API]] | |||
[[Category:Python Packaging]] | |||
Latest revision as of 17:11, 15 November 2018
Basics
Basic App
Run a Flask app that is bound to all network interfaces on the host, and listens on port 5000:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return "Hello, World!"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
If host and port are not specified, flask will only listen on the local network interface on port 5000.
if __name__ == '__main__':
app.run(debug=True)
Routes
Simple hello world route
A simple hello world route:
from flask import Flask
...
@app.route('/hello')
def hello():
return "Hello, World!"
Returning HTML
To return HTML, we can return it in a string:
from flask import Flask
...
@app.route('/get_html')
def get_html():
return "<h2>Flask Returns HTML Code</h2>"
Returning JSON
If we are writing an API, we want routes that return JSON. we can use Flask's jsonify function:
from flask import Flask, jsonify
...
@app.route('/list')
def list():
d = {'a' : 1, 'b' : 2, 'c' : 3}
return jsonify(d)
Rendering templates
This example shows how to take an integer variable from the URL and use it on an HTML template page:
from flask import Flask, render_template
...
@app.route('/sample/<int:sample_number>')
def sample(sample_number):
render_template('sample.html', sample_number=sample_number)
The contents of sample.html are given below:
<html>
<head>
<title>Sample {{sample_number}}</title>
</head>
<body>
<h2>{{sample_number}}</h2>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula.</p>
</body>
</html>
Raising errors
To abort with a 400 (server error), use the abort function
from flask import Flask, abort
...
@app.route('/how_to_abort')
def how_to_abort():
import random
if random.random() < 0.5:
abort(400)
else:
return "<h2>Hi there!</h2>"
Exceptions and errors
To write a custom exception that will return abort(YYY) (where YYY is an HTTP code), you can write an exception class that defines a status_code private variable:
class InvalidUsage(Exception):
status_code = 400
def __init__(self, message, status_code=None, payload=None):
Exception.__init__(self)
self.message = message
if status_code is not None:
self.status_code = status_code
self.payload = payload
def to_dict(self):
rv = dict(self.payload or ())
rv['message'] = self.message
return rv
Next, we need to create a handler for this type of error, and register it with our application:
from flask import jsonify
...
class InvalidUsage(Exception):
...
@app.errorhandler(InvalidUsage)
def handle_invalid_usage(error):
response = jsonify(error.to_dict())
response.status_code = error.status_code
return response
Described here in the flask documentation: http://flask.pocoo.org/docs/1.0/patterns/apierrors/
POST Endpoints
To deal with data sent via a POST request, use the request variable, imported from Flask, and get the POSTed data using request.json:
from flask import Flask, jsonify, abort, request
...
@app.route('/post_something',methods=['POST'])
def post_something():
if not request.json:
abort(400)
post_data = request.json
# Now render a template for the user
# and populate the template variables
# with data that was POSTed
render_template('posted.html',
title = post_data.get('title','A Pretty Boring Title'),
author = post_data.get('author','Anonymous Coward'),
color = post_data.get('color','blue'),
)
# NOTE:
# If you'd rather return json, just do
# return jsonify({'status':'ok'}), 200
Now we can POST data to the server by adding the JSON content type to a curl request, and pass data in using the -d flag. here's the curl request:
$ curl -i -H "Content-Type: application/json" -X POST -d '{"title":"My first post", "author":"Gladys Overwith", "color":"orange"}' http://localhost:5000/post_something
Packaging Flask Apps
Flask/Packaging - a page that covers how to bundle flask apps into a ready-to-distribute Python package
Resources
Flaskadillo
I put together a tutorial on how to use Flask. This is available in the flaskadillo repo:
Links
The Flask mega tutorial is really handy: http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
Micro blog example: https://stormpath.com/blog/build-a-flask-app-in-30-minutes