From charlesreid1

 
(30 intermediate revisions by the same user not shown)
Line 1: Line 1:
=Packaging Flask Apps=
=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
 
app = Flask(__name__)
 
@app.route('/')
def index():
    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__':
    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
 
...
 
@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


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


Instructions for deploying a Flask web app as a submodule in a Python module:
@app.route('/sample/<int:sample_number>')
def sample(sample_number):
    render_template('sample.html', sample_number=sample_number)
</pre>


First, your directory structure will look something like this:
The contents of <code>sample.html</code> are given below:


<pre>
<pre>
README.md
    <html>
setup.py
    <head>
mymodule/
    <title>Sample {{sample_number}}</title>
  __init__.py
    </head>
  submodule1/
    <body>
  submodule2/
        <h2>{{sample_number}}</h2>
  webapp/
        <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula.</p>
    __init__.py
     </body>
    additional_routes.py
     </html>
     templates/
      [...]
     static/
      [...]
</pre>
</pre>


Next, your setup.py file will look something like this:
===Raising errors===
 
To abort with a 400 (server error), use the abort function


<pre>
<pre>
config = {
from flask import Flask, abort
    '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)
@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>


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.
===Exceptions and errors===


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


To create an instance of your module's web app from anywhere, follow these steps:
<pre>
class InvalidUsage(Exception):
    status_code = 400


1. Install the module
    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


2. Import the webapp submodule:
    def to_dict(self):
        rv = dict(self.payload or ())
        rv['message'] = self.message
        return rv
</pre>
 
Next, we need to create a handler for this type of error, and register it with our application:


<pre>
<pre>
from mymodule.webapp import *
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>
</pre>


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


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


More information: http://www.plankandwhittle.com/packaging-a-flask-web-app/
[[Category:API]]
[[Category:Python]]
[[Category:Web]]
[[Category:Web Server]]
[[Category:REST API]]


Yet more information: http://flask.pocoo.org/docs/patterns/distribute/
[[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