[![Python unit CI][ff_python_unit_img]][ff_python_unit_link] [![Python lint CI][ff_python_lint_img]][ff_python_lint_link] [![Python conformance CI][ff_python_conformance_img]][ff_python_conformance_link]
An open source FaaS (Function as a service) framework for writing portable Python functions -- brought to you by the Google Cloud Functions team.
The Functions Framework lets you write lightweight functions that run in many different environments, including:
- Google Cloud Run Functions
- Your local development machine
- Knative-based environments
The framework allows you to go from:
def hello(request): return "Hello world!"
To:
curl http://my-url
All without needing to worry about writing an HTTP server or complicated request handling logic.
- Spin up a local development server for quick testing
- Invoke a function in response to a request
- Automatically unmarshal events conforming to the CloudEvents spec
- Portable between serverless platforms
Install the Functions Framework via pip:
pip install functions-framework
Or, for deployment, add the Functions Framework to your requirements.txt file:
functions-framework==3.*
Create an main.py file with the following contents:
import flask import functions_framework
@functions_framework.http def hello(request: flask.Request) -> flask.typing.ResponseReturnValue: return "Hello world!"
Your function is passed a single parameter,
(request), which is a FlaskRequestobject.
Run the following command:
functions-framework --target hello --debug
- Serving Flask app "hello" (lazy loading)
- Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
- Debug mode: on
- Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)
(You can also use functions-framework-python if you have multiple
language frameworks installed).
Open http://localhost:8080/ in your browser and see Hello world!.
Or send requests to this function using curl from another terminal window:
curl localhost:8080
Create an main.py file with the following contents:
import functions_framework from cloudevents.http.event import CloudEvent
@functions_framework.cloud_event def hello_cloud_event(cloud_event: CloudEvent) -> None: print(f"Received event with ID: {cloud_event['id']} and data {cloud_event.data}")
Your function is passed a single CloudEvent parameter.
Run the following command to run hello_cloud_event target locally:
functions-framework --target=hello_cloud_event
In a different terminal, curl the Functions Framework server:
curl -X POST localhost:8080
-H "Content-Type: application/cloudevents+json"
-d '{
"specversion" : "1.0",
"type" : "example.com.cloud.event",
"source" : "https://example.com/cloudevents/pull",
"subject" : "123",
"id" : "A234-1234-1234",
"time" : "2018-04-05T17:31:00Z",
"data" : "hello world"
}'
Output from the terminal running functions-framework:
Received event with ID: A234-1234-1234 and data hello world
More info on sending CloudEvents payloads, see examples/cloud_run_cloud_events instruction.
The framework includes an error handler that is similar to the
flask.Flask.errorhandler
function, which allows you to handle specific error types with a decorator:
import functions_framework
@functions_framework.errorhandler(ZeroDivisionError) def handle_zero_division(e): return "I'm a teapot", 418
def function(request): 1 / 0 return "Success", 200
This function will catch the ZeroDivisionError and return a different
response instead.
-
Create a
main.pyfile with the following contents:def hello(event, context): print("Received", context.event_id)
-
Start the Functions Framework on port 8080:
functions-framework --target=hello --signature-type=event --debug --port=8080
-
In a second terminal, start the Pub/Sub emulator on port 8085.
export PUBSUB_PROJECT_ID=my-project gcloud beta emulators pubsub start
--project=$PUBSUB_PROJECT_ID
--host-port=localhost:8085You should see the following after the Pub/Sub emulator has started successfully:
[pubsub] INFO: Server started, listening on 8085
-
In a third terminal, create a Pub/Sub topic and attach a push subscription to the topic, using
http://localhost:8080as its push endpoint. Publish some messages to the topic. Observe your function getting triggered by the Pub/Sub messages.export PUBSUB_PROJECT_ID=my-project export TOPIC_ID=my-topic export PUSH_SUBSCRIPTION_ID=my-subscription $(gcloud beta emulators pubsub env-init)
git clone https://github.com/googleapis/python-pubsub.git cd python-pubsub/samples/snippets/ pip install -r requirements.txt
python publisher.py $PUBSUB_PROJECT_ID create $TOPIC_ID python subscriber.py $PUBSUB_PROJECT_ID create-push $TOPIC_ID $PUSH_SUBSCRIPTION_ID http://localhost:8080 python publisher.py $PUBSUB_PROJECT_ID publish $TOPIC_ID
You should see the following after the commands have run successfully:
Created topic: projects/my-project/topics/my-topic
topic: "projects/my-project/topics/my-topic" push_config { push_endpoint: "http://localhost:8080" } ack_deadline_seconds: 10 message_retention_duration { seconds: 604800 } . Endpoint for subscription is: http://localhost:8080
1 2 3 4 5 6 7 8 9 Published messages to projects/my-project/topics/my-topic.
And in the terminal where the Functions Framework is running:
* Serving Flask app "hello" (lazy loading)- Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
- Debug mode: on
- Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)
- Restarting with fsevents reloader
- Debugger is active!
- Debugger PIN: 911-794-046 Received 1 127.0.0.1 - - [11/Aug/2021 14:42:22] "POST / HTTP/1.1" 200 - Received 2 127.0.0.1 - - [11/Aug/2021 14:42:22] "POST / HTTP/1.1" 200 - Received 5 127.0.0.1 - - [11/Aug/2021 14:42:22] "POST / HTTP/1.1" 200 - Received 6 127.0.0.1 - - [11/Aug/2021 14:42:22] "POST / HTTP/1.1" 200 - Received 7 127.0.0.1 - - [11/Aug/2021 14:42:22] "POST / HTTP/1.1" 200 - Received 8 127.0.0.1 - - [11/Aug/2021 14:42:22] "POST / HTTP/1.1" 200 - Received 9 127.0.0.1 - - [11/Aug/2021 14:42:39] "POST / HTTP/1.1" 200 - Received 3 127.0.0.1 - - [11/Aug/2021 14:42:39] "POST / HTTP/1.1" 200 - Received 4 127.0.0.1 - - [11/Aug/2021 14:42:39] "POST / HTTP/1.1" 200 -
For more details on extracting data from a Pub/Sub event, see https://cloud.google.com/pubsub/docs/push