Skip to content

Commit

Permalink
Clarify use and purpose of templates in this repo
Browse files Browse the repository at this point in the history
Clarifies expectations for usage of the templates in this
repo along with an update to the python3-flask template so that
it provides a better upgrade path.

Examples added for python3-flask to show how to return a HTTP
error or status code.

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
  • Loading branch information
alexellis committed Jun 10, 2020
1 parent e815593 commit 7411356
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 15 deletions.
109 changes: 97 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,137 @@ OpenFaaS Python Flask Templates
The Python Flask templates that make use of the incubator project [of-watchdog](https://github.com/openfaas-incubator/of-watchdog).

Templates available in this repository:

- python27-flask
- python3-flask
- python3-flask-debian
- python3-flask-armhf

- python3-http
- python3-http-debian
- python3-http-armhf

Notes:
- To build and deploy a function for Raspberry Pi or ARMv7 in general, use the language templates ending in *-armhf*

## Picking your template

The templates named `python*-flask*` are designed as a drop-in replacement for the classic `python3` template, but using the more efficient of-watchdog. The move to use flask as an underlying framework allows for greater control over the HTTP request and response.

Those templates named `python*-http*` are designed to offer full control over the HTTP request and response. Flask is used as an underlying framework.

The `witness` HTTP server is used along with Flask for all templates.

Are you referencing pip modules which require a native build toolchain? It's advisable to use the template with a `-debian` suffix in this case. The Debian images are larger, however they are usually more efficient for use with modules like `numpy` and `pandas`.

## Downloading the templates

Using template pull:

```bash
faas template pull https://github.com/openfaas-incubator/python-flask-template
```
$ faas template pull https://github.com/openfaas-incubator/python-flask-template

Using template store:

```bash
faas template store pull python3-flask
```

# Using the python27-flask/python3-flask templates
# Using the python3-flask template

Create a new function

```
$ faas new --lang python27-flask <fn-name>
export OPENFAAS_PREFIX=alexellis2
export FN="tester"
faas new --lang python3-flask $FN
```

Build, push, and deploy

```
$ faas up -f <fn-name>.yml
faas up -f $FN.yml
```

Test the new function

```
$ echo -n content | faas invoke <fn-name>
echo -n content | faas invoke $FN
```

## Example of returning a string

```python
def handle(req):
"""handle a request to the function
Args:
req (str): request body
"""

return "Hi" + str(req)
```

## Example of returning a custom HTTP code

```python
def handle(req):
return "request accepted", 201
```

## Example of returning a custom HTTP code and content-type

```python
def handle(req):
return "request accepted", 201, {"Content-Type":"binary/octet-stream"}
```

## Example of accepting raw bytes in the request

Update stack.yml:

```yaml
environment:
RAW_BODY: True
```

> Note: the value for `RAW_BODY` is case-sensitive.
```python
def handle(req):
"""handle a request to the function
Args:
req (str): request body
"""

# req is bytes, so an input of "hello" returns i.e. b'hello'
return string(req)
```

# Using the python3-http templates

Create a new function

```
$ faas new --lang python3-http <fn-name>
export OPENFAAS_PREFIX=alexellis2
export FN="tester"
faas new --lang python3-http $FN
```

Build, push, and deploy

```
$ faas up -f <fn-name>.yml
```
Set your OpenFaaS gateway URL. For example:
```
$ OPENFAAS_URL=http://127.0.0.1:8080
faas up -f $FN.yml
```

Test the new function

```
$ curl -i $OPENFAAS_URL/function/<fn-name>
echo -n content | faas invoke $FN
```

## Event and Context Data

The function handler is passed two arguments, *event* and *context*.

*event* contains data about the request, including:
Expand All @@ -66,12 +148,15 @@ The function handler is passed two arguments, *event* and *context*.
- hostname

## Response Bodies

By default, the template will automatically attempt to set the correct Content-Type header for you based on the type of response.

For example, returning a dict object type will automatically attach the header `Content-Type: application/json` and returning a string type will automatically attach the `Content-Type: text/html, charset=utf-8` for you.

## Example usage

### Custom status codes and response bodies

Successful response status code and JSON response body
```python
def handle(event, context):
Expand Down
14 changes: 13 additions & 1 deletion template/python3-flask-armhf/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@
from flask import Flask, request
from function import handler
from waitress import serve
import os

app = Flask(__name__)

# distutils.util.strtobool() can throw an exception
def is_true(val):
return len(val) > 0 and val.lower() == "true" or val == "1"

@app.before_request
def fix_transfer_encoding():
"""
Expand All @@ -22,7 +27,14 @@ def fix_transfer_encoding():
@app.route("/", defaults={"path": ""}, methods=["POST", "GET"])
@app.route("/<path:path>", methods=["POST", "GET"])
def main_route(path):
ret = handler.handle(request.get_data())
raw_body = os.getenv("RAW_BODY")

as_text = True

if is_true(raw_body):
as_text = False

ret = handler.handle(request.get_data(as_text=as_text))
return ret

if __name__ == '__main__':
Expand Down
14 changes: 13 additions & 1 deletion template/python3-flask-debian/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@
from flask import Flask, request
from function import handler
from waitress import serve
import os

app = Flask(__name__)

# distutils.util.strtobool() can throw an exception
def is_true(val):
return len(val) > 0 and val.lower() == "true" or val == "1"

@app.before_request
def fix_transfer_encoding():
"""
Expand All @@ -22,7 +27,14 @@ def fix_transfer_encoding():
@app.route("/", defaults={"path": ""}, methods=["POST", "GET"])
@app.route("/<path:path>", methods=["POST", "GET"])
def main_route(path):
ret = handler.handle(request.get_data())
raw_body = os.getenv("RAW_BODY")

as_text = True

if is_true(raw_body):
as_text = False

ret = handler.handle(request.get_data(as_text=as_text))
return ret

if __name__ == '__main__':
Expand Down
14 changes: 13 additions & 1 deletion template/python3-flask/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@
from flask import Flask, request
from function import handler
from waitress import serve
import os

app = Flask(__name__)

# distutils.util.strtobool() can throw an exception
def is_true(val):
return len(val) > 0 and val.lower() == "true" or val == "1"

@app.before_request
def fix_transfer_encoding():
"""
Expand All @@ -22,7 +27,14 @@ def fix_transfer_encoding():
@app.route("/", defaults={"path": ""}, methods=["POST", "GET"])
@app.route("/<path:path>", methods=["POST", "GET"])
def main_route(path):
ret = handler.handle(request.get_data())
raw_body = os.getenv("RAW_BODY")

as_text = True

if is_true(raw_body):
as_text = False

ret = handler.handle(request.get_data(as_text=as_text))
return ret

if __name__ == '__main__':
Expand Down

0 comments on commit 7411356

Please sign in to comment.