From charlesreid1

No edit summary
 
(15 intermediate revisions by the same user not shown)
Line 1: Line 1:
=Basics=
=Basics=


==App==
==Basic App==
 
===Hello World Application===


Run a Flask app that is bound to all network interfaces on the host, and listens on port 5000:
Run a Flask app that is bound to all network interfaces on the host, and listens on port 5000:
Line 29: Line 27:
==Routes==
==Routes==


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


<pre>
<pre>
from flask import Flask
...
@app.route('/hello')
@app.route('/hello')
def hello():
def hello():
     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:


<pre>
<pre>
from flask import Flask
...
@app.route('/get_html')
@app.route('/get_html')
def get_html():
def get_html():
     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 58: Line 70:
</pre>
</pre>


===Rendering templates===


=RESTful API=
This example shows how to take an integer variable from the URL and use it on an HTML template page:
 
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.
 
==Hello World==
 
Let's put our Flask hello world app in <code>run.py</code>:


<pre>
<pre>
from flask import Flask
from flask import Flask, render_template


app = Flask(__name__)
...
 
@app.route('/')
def index():
    return "Hello, World!"


if __name__ == '__main__':
@app.route('/sample/<int:sample_number>')
     app.run(debug=True)
def sample(sample_number):
     render_template('sample.html', sample_number=sample_number)
</pre>
</pre>


now we run it with <code>python run.py</code>
The contents of <code>sample.html</code> are given below:


==Return Some Data with JSON==
<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>


Now let's return some data from the RESTful server to the client (perhaps a sensor on a Raspberry Pi running the RESTful API):
===Raising errors===


<source lang="python">
To abort with a 400 (server error), use the abort function
from flask import Flask, jsonify


app = Flask(__name__)
<pre>
from flask import Flask, abort


data = [
...
    {
        'sensor_id': 1,
        'time': u'2005-01-01 22:23:04',
        'temparature1': 114.15,
        'temparature2': 132.92,
        'alarm': False
    },
    {
        'sensor_id': 1,
        'time': u'2005-01-01 22:23:05',
        'temparature1': 118.66,
        'temparature2': 158.41,
        'alarm': False
    }
]


@app.route('sensor/id/1/data', methods=['GET'])
@app.route('/how_to_abort')
def get_tasks():
def how_to_abort():
     return jsonify({'tasks': tasks})
     import random
    if random.random() < 0.5:
        abort(400)
    else:
        return "<h2>Hi there!</h2>"
</pre>


if __name__ == '__main__':
===Exceptions and errors===
    app.run(debug=True)
</source>


Now you can request that resource using CURL:
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 http://localhost:5000/sensor/id/1/data
class InvalidUsage(Exception):
HTTP/1.0 200 OK
    status_code = 400
Content-Type: application/json
 
Content-Length: 294
    def __init__(self, message, status_code=None, payload=None):
Server: Werkzeug/0.8.3 Python/2.7.3
        Exception.__init__(self)
Date: Mon, 20 May 2013 04:53:53 GMT
        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 ())
  "data": [
         rv['message'] = self.message
     {
         return rv
        'sensor_id': 1,
        'time': u'2005-01-01 22:23:04',
         'temparature1': 114.15,
         'temparature2': 132.92,
        'alarm': False
    },
    {
        'sensor_id': 1,
        'time': u'2005-01-01 22:23:05',
        'temparature1': 118.66,
         'temparature2': 158.41,
        'alarm': False
    }
  ]
}
</pre>
</pre>


==Send Some Data with POST==
Next, we need to create a handler for this type of error, and register it with our application:


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


<source lang="python">
...
from flask import request


@app.route('/todo/api/v1.0/tasks', methods=['POST'])
class InvalidUsage(Exception):
def create_task():
    if not request.json or not 'title' in request.json:
        abort(400)
    task = {
        'id': tasks[-1]['id'] + 1,
        'title': request.json['title'],
        'description': request.json.get('description', ""),
        'done': False
    }
    tasks.append(task)
    return jsonify({'task': task}), 201
</source>


and the corresponding output when we POST data to the server:
...
 
<pre>
$ curl -i -H "Content-Type: application/json" -X POST -d '{"title":"Read a book"}' http://localhost:5000/todo/api/v1.0/tasks
HTTP/1.0 201 Created
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


{
@app.errorhandler(InvalidUsage)
  "task": {
def handle_invalid_usage(error):
     "description": "",
     response = jsonify(error.to_dict())
    "done": false,
     response.status_code = error.status_code
     "id": 3,
     return response
     "title": "Read a book"
  }
}
</pre>
</pre>


=Packaging Flask Apps=


==Deploying Flask Web App as Submodule==
Described here in the flask documentation: http://flask.pocoo.org/docs/1.0/patterns/apierrors/


Instructions for deploying a Flask web app as a submodule in a Python module:
==POST Endpoints==


First, your directory structure will look something like this:
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>
README.md
from flask import Flask, jsonify, abort, request
setup.py
mymodule/
  __init__.py
  submodule1/
  submodule2/
  webapp/
    __init__.py
    additional_routes.py
    templates/
      [...]
    static/
      [...]
</pre>


Next, your setup.py file will look something like this:
...


<pre>
@app.route('/post_something',methods=['POST'])
config = {
def post_something():
    'description': 'My Module',
     if not request.json:
    'install_requires': ['flask'],
         abort(400)
    'packages': ['mymodule','mymodule.submodule1','mymodule.submodule2','mymodule.webapp'],
    post_data = request.json
    '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.  
    # 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'),
    )


Now you can install your module with <code>python setup.py install</code>, and your module is available to use from anywhere.


To create an instance of your module's web app from anywhere, follow these steps:
    # NOTE:
    # If you'd rather return json, just do
    # return jsonify({'status':'ok'}), 200


1. Install the module
</pre>


2. Import the webapp submodule:
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>
from mymodule.webapp import *
$ 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>


3. Start the webapp:
=Packaging Flask Apps=


<pre>
[[Flask/Packaging]] - a page that covers how to bundle flask apps into a ready-to-distribute Python package
app.run(debug=True)
 
</pre>
=Resources=


Voila!
==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




=Resources=


==Basics==
==Links==


The Flask mega tutorial is really handy: http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
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
Micro blog example: https://stormpath.com/blog/build-a-flask-app-in-30-minutes
==Bundling==
Official flask site: patterns for distributing flask apps: http://flask.pocoo.org/docs/patterns/distribute/
Packaging a flask app: http://www.plankandwhittle.com/packaging-a-flask-web-app/


=Flags=
=Flags=
Line 278: Line 223:
[[Category:Web Server]]
[[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