Skip to content

Commit 7411356

Browse files
committed
Clarify use and purpose of templates in this repo
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) <[email protected]>
1 parent e815593 commit 7411356

File tree

4 files changed

+136
-15
lines changed

4 files changed

+136
-15
lines changed

README.md

Lines changed: 97 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,55 +4,137 @@ OpenFaaS Python Flask Templates
44
The Python Flask templates that make use of the incubator project [of-watchdog](https://github.com/openfaas-incubator/of-watchdog).
55

66
Templates available in this repository:
7+
78
- python27-flask
89
- python3-flask
910
- python3-flask-debian
1011
- python3-flask-armhf
12+
1113
- python3-http
1214
- python3-http-debian
1315
- python3-http-armhf
1416

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

20+
## Picking your template
21+
22+
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.
23+
24+
Those templates named `python*-http*` are designed to offer full control over the HTTP request and response. Flask is used as an underlying framework.
25+
26+
The `witness` HTTP server is used along with Flask for all templates.
27+
28+
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`.
29+
1830
## Downloading the templates
31+
32+
Using template pull:
33+
34+
```bash
35+
faas template pull https://github.com/openfaas-incubator/python-flask-template
1936
```
20-
$ faas template pull https://github.com/openfaas-incubator/python-flask-template
37+
38+
Using template store:
39+
40+
```bash
41+
faas template store pull python3-flask
2142
```
2243

23-
# Using the python27-flask/python3-flask templates
44+
# Using the python3-flask template
45+
2446
Create a new function
47+
2548
```
26-
$ faas new --lang python27-flask <fn-name>
49+
export OPENFAAS_PREFIX=alexellis2
50+
export FN="tester"
51+
faas new --lang python3-flask $FN
2752
```
53+
2854
Build, push, and deploy
55+
2956
```
30-
$ faas up -f <fn-name>.yml
57+
faas up -f $FN.yml
3158
```
59+
3260
Test the new function
61+
3362
```
34-
$ echo -n content | faas invoke <fn-name>
63+
echo -n content | faas invoke $FN
64+
```
65+
66+
## Example of returning a string
67+
68+
```python
69+
def handle(req):
70+
"""handle a request to the function
71+
Args:
72+
req (str): request body
73+
"""
74+
75+
return "Hi" + str(req)
76+
```
77+
78+
## Example of returning a custom HTTP code
79+
80+
```python
81+
def handle(req):
82+
return "request accepted", 201
83+
```
84+
85+
## Example of returning a custom HTTP code and content-type
86+
87+
```python
88+
def handle(req):
89+
return "request accepted", 201, {"Content-Type":"binary/octet-stream"}
90+
```
91+
92+
## Example of accepting raw bytes in the request
93+
94+
Update stack.yml:
95+
96+
```yaml
97+
environment:
98+
RAW_BODY: True
99+
```
100+
101+
> Note: the value for `RAW_BODY` is case-sensitive.
102+
103+
```python
104+
def handle(req):
105+
"""handle a request to the function
106+
Args:
107+
req (str): request body
108+
"""
109+
110+
# req is bytes, so an input of "hello" returns i.e. b'hello'
111+
return string(req)
35112
```
36113

37114
# Using the python3-http templates
115+
38116
Create a new function
117+
39118
```
40-
$ faas new --lang python3-http <fn-name>
119+
export OPENFAAS_PREFIX=alexellis2
120+
export FN="tester"
121+
faas new --lang python3-http $FN
41122
```
123+
42124
Build, push, and deploy
125+
43126
```
44-
$ faas up -f <fn-name>.yml
45-
```
46-
Set your OpenFaaS gateway URL. For example:
47-
```
48-
$ OPENFAAS_URL=http://127.0.0.1:8080
127+
faas up -f $FN.yml
49128
```
129+
50130
Test the new function
131+
51132
```
52-
$ curl -i $OPENFAAS_URL/function/<fn-name>
133+
echo -n content | faas invoke $FN
53134
```
54135
55136
## Event and Context Data
137+
56138
The function handler is passed two arguments, *event* and *context*.
57139
58140
*event* contains data about the request, including:
@@ -66,12 +148,15 @@ The function handler is passed two arguments, *event* and *context*.
66148
- hostname
67149
68150
## Response Bodies
151+
69152
By default, the template will automatically attempt to set the correct Content-Type header for you based on the type of response.
70153
71154
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.
72155
73156
## Example usage
157+
74158
### Custom status codes and response bodies
159+
75160
Successful response status code and JSON response body
76161
```python
77162
def handle(event, context):

template/python3-flask-armhf/index.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@
44
from flask import Flask, request
55
from function import handler
66
from waitress import serve
7+
import os
78

89
app = Flask(__name__)
910

11+
# distutils.util.strtobool() can throw an exception
12+
def is_true(val):
13+
return len(val) > 0 and val.lower() == "true" or val == "1"
14+
1015
@app.before_request
1116
def fix_transfer_encoding():
1217
"""
@@ -22,7 +27,14 @@ def fix_transfer_encoding():
2227
@app.route("/", defaults={"path": ""}, methods=["POST", "GET"])
2328
@app.route("/<path:path>", methods=["POST", "GET"])
2429
def main_route(path):
25-
ret = handler.handle(request.get_data())
30+
raw_body = os.getenv("RAW_BODY")
31+
32+
as_text = True
33+
34+
if is_true(raw_body):
35+
as_text = False
36+
37+
ret = handler.handle(request.get_data(as_text=as_text))
2638
return ret
2739

2840
if __name__ == '__main__':

template/python3-flask-debian/index.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@
44
from flask import Flask, request
55
from function import handler
66
from waitress import serve
7+
import os
78

89
app = Flask(__name__)
910

11+
# distutils.util.strtobool() can throw an exception
12+
def is_true(val):
13+
return len(val) > 0 and val.lower() == "true" or val == "1"
14+
1015
@app.before_request
1116
def fix_transfer_encoding():
1217
"""
@@ -22,7 +27,14 @@ def fix_transfer_encoding():
2227
@app.route("/", defaults={"path": ""}, methods=["POST", "GET"])
2328
@app.route("/<path:path>", methods=["POST", "GET"])
2429
def main_route(path):
25-
ret = handler.handle(request.get_data())
30+
raw_body = os.getenv("RAW_BODY")
31+
32+
as_text = True
33+
34+
if is_true(raw_body):
35+
as_text = False
36+
37+
ret = handler.handle(request.get_data(as_text=as_text))
2638
return ret
2739

2840
if __name__ == '__main__':

template/python3-flask/index.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@
44
from flask import Flask, request
55
from function import handler
66
from waitress import serve
7+
import os
78

89
app = Flask(__name__)
910

11+
# distutils.util.strtobool() can throw an exception
12+
def is_true(val):
13+
return len(val) > 0 and val.lower() == "true" or val == "1"
14+
1015
@app.before_request
1116
def fix_transfer_encoding():
1217
"""
@@ -22,7 +27,14 @@ def fix_transfer_encoding():
2227
@app.route("/", defaults={"path": ""}, methods=["POST", "GET"])
2328
@app.route("/<path:path>", methods=["POST", "GET"])
2429
def main_route(path):
25-
ret = handler.handle(request.get_data())
30+
raw_body = os.getenv("RAW_BODY")
31+
32+
as_text = True
33+
34+
if is_true(raw_body):
35+
as_text = False
36+
37+
ret = handler.handle(request.get_data(as_text=as_text))
2638
return ret
2739

2840
if __name__ == '__main__':

0 commit comments

Comments
 (0)