> ## Documentation Index
> Fetch the complete documentation index at: https://anaconda.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploying a Flask application

The process of deploying a Flask application (website and REST APIs) on Data Science & AI Workbench involves the following:

1. Configuring Flask to [run behind a proxy](#running-behind-an-https-proxy)
2. Enabling Anaconda Project [HTTP command-line arguments](#enabling-command-line-arguments)
3. Running Flask [on the deployed host and port](#running-your-flask-application)

Here is a small Flask application that includes the call to `.run()`. The file is saved to `server.py`.

This Flask application was written using [Blueprints](https://flask.palletsprojects.com/en/stable/blueprints/), which is useful
for separating components when working with a large Flask application.

Here, the nested block in `if __name__ == '__main__'` could be in a separate
file from the `'hello'` Blueprint.

```py theme={null}
from flask import Flask, Blueprint

hello = Blueprint('hello', __name__)

@hello.route('/')
def hello_world():
    return 'Hello, World!'

if __name__ == '__main__':
    app = Flask(__name__)
    app.register_blueprint(hello, url_prefix='/')

    app.run()
```

## Running behind an HTTPS proxy

Workbench maintains all HTTPS connections into and out of
the server and deployed instances. When writing a Flask app, you only
need to inform it that will be accessed from behind the proxy provided
by Workbench.

The simplest way to do this is with the `ProxyFix` function from `werkzeug`.
More information about proxies is provided [here](https://flask-dance.readthedocs.io/en/latest/proxies.html).

```py theme={null}
from flask import Flask, Blueprint
from werkzeug.contrib.fixers import ProxyFix

hello = Blueprint('hello', __name__)

@hello.route('/')
def hello_world():
    return 'Hello, World!'

if __name__ == '__main__':
    app = Flask(__name__)
    app.register_blueprint(hello, url_prefix='/')

    app.wsgi_app = ProxyFix(app.wsgi_app)
    app.run()
```

## Enabling command-line arguments

In your `anaconda-project.yml` file, you define a deployable command as follows:

```yaml theme={null}
commands:
  default:
    unix: python ${PROJECT_DIR}/server.py
    supports_http_options: true
```

The flag `supports_http_options` means that `server.py` is expected to act on the following command line arguments defined in the [Anaconda Project Reference](https://anaconda-project.readthedocs.io/en/latest/user-guide/reference.html#http-commands).

This is easily accomplished by adding the following `argparse` code before calling `app.run()` in `server.py`

```py theme={null}
import sys
from argparse import ArgumentParser

# ... the Flask application blueprint

if __name__ == '__main__':
    # arg parser for the standard anaconda-project options
    parser = ArgumentParser(prog="hello_world",
                            description="Simple Flask Application")
    parser.add_argument('--anaconda-project-host', action='append', default=[],
                        help='Hostname to allow in requests')
    parser.add_argument('--anaconda-project-port', action='store', default=8086, type=int,
                        help='Port to listen on')
    parser.add_argument('--anaconda-project-iframe-hosts',
                        action='append',
                        help='Space-separated hosts which can embed us in an iframe per our Content-Security-Policy')
    parser.add_argument('--anaconda-project-no-browser', action='store_true',
                        default=False,
                        help='Disable opening in a browser')
    parser.add_argument('--anaconda-project-use-xheaders',
                        action='store_true',
                        default=False,
                        help='Trust X-headers from reverse proxy')
    parser.add_argument('--anaconda-project-url-prefix', action='store', default='',
                        help='Prefix in front of urls')
    parser.add_argument('--anaconda-project-address',
                        action='store',
                        default='0.0.0.0',
                        help='IP address the application should listen on.')

    args = parser.parse_args()
```

## Running your Flask application

The final step is to configure the Flask application with the
Anaconda Project HTTP values and call `app.run()`. Note that
registering the Blueprint provides a convenient way to deploy
your application without having to rewrite the routes.

```py theme={null}
# ... the flask application blueprint

if __name__ == '__main__':
    # ... parse command line arguments

    app = Flask(__name__)
    app.register_blueprint(hello, url_prefix=args.anaconda_project_url_prefix)

    app.config['PREFERRED_URL_SCHEME'] = 'https'

    app.wsgi_app = ProxyFix(app.wsgi_app)
    app.run(host=args.anaconda_project_address, port=args.anaconda_project_port)
```

Here is the complete code for the Hello World application.

```py theme={null}
import sys
from flask import Flask, Blueprint
from argparse import ArgumentParser
from werkzeug.contrib.fixers import ProxyFix

hello = Blueprint('hello', __name__)

@hello.route('/')
def hello_world():
    return "Hello, World!"

if __name__ == '__main__':

    # arg parser for the standard anaconda-project options
    parser = ArgumentParser(prog="hello_world",
                            description="Simple Flask Application")
    parser.add_argument('--anaconda-project-host', action='append', default=[],
                        help='Hostname to allow in requests')
    parser.add_argument('--anaconda-project-port', action='store', default=8086, type=int,
                        help='Port to listen on')
    parser.add_argument('--anaconda-project-iframe-hosts',
                        action='append',
                        help='Space-separated hosts which can embed us in an iframe per our Content-Security-Policy')
    parser.add_argument('--anaconda-project-no-browser', action='store_true',
                        default=False,
                        help='Disable opening in a browser')
    parser.add_argument('--anaconda-project-use-xheaders',
                        action='store_true',
                        default=False,
                        help='Trust X-headers from reverse proxy')
    parser.add_argument('--anaconda-project-url-prefix', action='store', default='',
                        help='Prefix in front of urls')
    parser.add_argument('--anaconda-project-address',
                        action='store',
                        default='0.0.0.0',
                        help='IP address the application should listen on.')

    args = parser.parse_args()

    app = Flask(__name__)
    app.register_blueprint(hello, url_prefix = args.anaconda_project_url_prefix)

    app.config['PREFERRED_URL_SCHEME'] = 'https'

    app.wsgi_app = ProxyFix(app.wsgi_app)
    app.run(host=args.anaconda_project_address, port=args.anaconda_project_port)
```
