From charlesreid1

 
(9 intermediate revisions by the same user not shown)
Line 27: Line 27:
==Routes==
==Routes==


Simple hello world route:
===Simple hello world route===
 
A simple hello world route:


<pre>
<pre>
Line 38: Line 40:
     return "Hello, World!"
     return "Hello, World!"
</pre>
</pre>
===Returning HTML===


To return HTML, we can return it in a string:
To return HTML, we can return it in a string:
Line 50: Line 54:
     return "<h2>Flask Returns HTML Code</h2>"
     return "<h2>Flask Returns HTML Code</h2>"
</pre>
</pre>
===Returning JSON===


If we are writing an API, we want routes that return JSON. we can use Flask's jsonify function:
If we are writing an API, we want routes that return JSON. we can use Flask's jsonify function:
Line 64: Line 70:
</pre>
</pre>


=RESTful API=
===Rendering templates===


We can use Flask to design and implement a RESTful API service. Flask will be a server and interpret between URLs and Python actions. Note that this is particularly handy if you're designing an internet-of-things thing, as you can install Flask on a [[RaspberryPi]], and now you have a RESTful API for accessing your Raspberry Pi! If you take it a step further, you can control the GPIO pins on the Raspberry Pi, and make the Pi do things with your hardware and circuitry based on your API actions.
This example shows how to take an integer variable from the URL and use it on an HTML template page:


==Hello World==
<pre>
from flask import Flask, render_template


Let's put our Flask hello world app in <code>run.py</code>:
...


<pre>
@app.route('/sample/<int:sample_number>')
from flask import Flask
def sample(sample_number):
    render_template('sample.html', sample_number=sample_number)
</pre>


app = Flask(__name__)
The contents of <code>sample.html</code> are given below:


@app.route('/')
<pre>
def index():
    <html>
     return "Hello, World!"
    <head>
 
    <title>Sample {{sample_number}}</title>
if __name__ == '__main__':
    </head>
     app.run(debug=True)
     <body>
        <h2>{{sample_number}}</h2>
        <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula.</p>
    </body>
     </html>
</pre>
</pre>


now we run it with <code>python run.py</code>
===Raising errors===


==Send Some Data with POST==
To abort with a 400 (server error), use the abort function


You can also send some data with POST requests:
<pre>
from flask import Flask, abort


<pre>
...
from flask import request


@app.route('/todo/api/v1.0/tasks', methods=['POST'])
@app.route('/how_to_abort')
def create_task():
def how_to_abort():
     if not request.json or not 'title' in request.json:
    import random
     if random.random() < 0.5:
         abort(400)
         abort(400)
     task = {
     else:
        'id': tasks[-1]['id'] + 1,
         return "<h2>Hi there!</h2>"
         'title': request.json['title'],
        'description': request.json.get('description', ""),
        'done': False
    }
    tasks.append(task)
    return jsonify({'task': task}), 201
</pre>
</pre>


and the corresponding output when we POST data to the server:
===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>
$ curl -i -H "Content-Type: application/json" -X POST -d '{"title":"Read a book"}' http://localhost:5000/todo/api/v1.0/tasks
class InvalidUsage(Exception):
HTTP/1.0 201 Created
    status_code = 400
Content-Type: application/json
Content-Length: 104
Server: Werkzeug/0.8.3 Python/2.7.3
Date: Mon, 20 May 2013 05:56:21 GMT


{
    def __init__(self, message, status_code=None, payload=None):
  "task": {
        Exception.__init__(self)
    "description": "",
        self.message = message
    "done": false,
        if status_code is not None:
     "id": 3,
            self.status_code = status_code
    "title": "Read a book"
        self.payload = payload
  }
 
}
     def to_dict(self):
        rv = dict(self.payload or ())
        rv['message'] = self.message
        return rv
</pre>
</pre>


=Packaging Flask Apps=
Next, we need to create a handler for this type of error, and register it with our application:
 
<pre>
from flask import jsonify


==Deploying Flask Web App as Submodule==
...


Instructions for deploying a Flask web app as a submodule in a Python module:
class InvalidUsage(Exception):


First, your directory structure will look something like this:
...


<pre>
@app.errorhandler(InvalidUsage)
README.md
def handle_invalid_usage(error):
setup.py
     response = jsonify(error.to_dict())
mymodule/
     response.status_code = error.status_code
  __init__.py
     return response
  submodule1/
  submodule2/
  webapp/
     __init__.py
     additional_routes.py
    templates/
      [...]
     static/
      [...]
</pre>
</pre>


Next, your setup.py file will look something like this:
 
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>
config = {
from flask import Flask, jsonify, abort, request
    'description': 'My Module',
    'install_requires': ['flask'],
    'packages': ['mymodule','mymodule.submodule1','mymodule.submodule2','mymodule.webapp'],
    'include_package_data' : True,
    'package_data' : {
        'templates' : 'mymodule/webapp/templates/*',
        'static' : 'mymodule/webapp/static/*'
        },
    'scripts': [],
    'name': 'mulch',
    'zip_safe' : False
}


setup(**config)
...
</pre>


The key lines here are <code>include_package_data</code> and <code>package_data</code>, which will also install your non-Python template and static files with your module.  
@app.route('/post_something',methods=['POST'])
def post_something():
    if not request.json:
        abort(400)
    post_data = request.json


Now you can install your module with <code>python setup.py install</code>, and your module is available to use from anywhere.
    # 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'),
    )


To create an instance of your module's web app from anywhere, follow these steps:


1. Install the module
    # NOTE:
    # If you'd rather return json, just do
    # return jsonify({'status':'ok'}), 200


2. Import the webapp submodule:
<pre>
from mymodule.webapp import *
</pre>
</pre>


3. Start the webapp:
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>
app.run(debug=True)
$ 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>


Voila!
=Packaging Flask Apps=


[[Flask/Packaging]] - a page that covers how to bundle flask apps into a ready-to-distribute Python package


=Resources=


==Flaskadillo==


=Resources=
I put together a tutorial on how to use Flask. This is available in the flaskadillo repo:


==Basics==
* https://git.charlesreid1.com/charlesreid1/flaskadillo
* https://github.com/charlesreid1/flaskadillo


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


==Bundling==
==Links==


Official flask site: patterns for distributing flask apps: http://flask.pocoo.org/docs/patterns/distribute/
The Flask mega tutorial is really handy: http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world


Packaging a flask app: http://www.plankandwhittle.com/packaging-a-flask-web-app/
Micro blog example: https://stormpath.com/blog/build-a-flask-app-in-30-minutes


=Flags=
=Flags=
Line 216: Line 221:
[[Category:Python]]
[[Category:Python]]
[[Category:Web]]
[[Category:Web]]
[[Category:Web Server]]
[[Category:REST API]]
[[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

Flags