Webhooks
With webhooks you can create REST endpoints which create Cloudomation executions when called.
Use Cases
Use webhooks to
- start Cloudomation executions from third party systems
- receive notifications from third party systems
- receive callbacks from asynchrounous processes running in third party systems
- create custom status HTML pages which display information gathered from Cloudomation
- expose information or functionality to consumers which do not have a Cloudomation user
Concept
As long as an enabled webhook exists in Cloudomation the REST endpoint is available to receive calls.
HTTP method
The endpoint accepts the HTTP methods GET
, DELETE
, HEAD
, POST
, PUT
, and PATCH
.
The method which was used is passed to the execution.
If the HTTP method allows for a body payload and a body payload was provided, it is also passed
to the execution.
A HTTP GET
request should only be used to retrieve a resource, while a HTTP POST
request
should be used to create a resource. Calling a Cloudomation webhook creates an execution.
Thus the recommended way to call a webhook is by using a POST
request. For compatibility
reasons Cloudomation also allows calling webhooks using a GET
request.
Consider a webhook named "captain" in the workspace "jollyroger".
curl https://jollyroger.cloudomation.com/api/latest/webhook/captain/call# the execution will receive in the input_value:# {"method": "GET"}curl -X PUT https://jollyroger.cloudomation.com/api/latest/webhook/captain/call# the execution will receive in the input_value:# {"method": "PUT"}curl -X DELETE https://jollyroger.cloudomation.com/api/latest/webhook/captain/call# the execution will receive in the input_value:# {"method": "DELETE"}
Path
Each webhook creates a base URL where it can be called. All calls below that base URL are also accepted. The path which was used is also passed to the execution.
Consider a webhook named "captain" in the workspace "jollyroger".
curl https://jollyroger.cloudomation.com/api/latest/webhook/captain/call# the execution will receive in the input_value:# {"path": None}curl https://jollyroger.cloudomation.com/api/latest/webhook/captain/call/# the execution will receive in the input_value:# {"path": ""}curl https://jollyroger.cloudomation.com/api/latest/webhook/captain/call/some/path# the execution will receive in the input_value:# {"path": "some/path"}
Headers
All HTTP headers which are sent from the client are passed to the execution.
Consider a webhook named "captain" in the workspace "jollyroger".
curl https://jollyroger.cloudomation.com/api/latest/webhook/captain/call -H "my-header: value"# the execution will receive in the input_value:# {"headers": {"my-header": "value"}}
Query parameters
All query parameters which are used are passed to the execution.
Consider a webhook named "captain" in the workspace "jollyroger".
curl https://jollyroger.cloudomation.com/api/latest/webhook/captain/call# the execution will receive in the input_value:# {"query": {}}curl https://jollyroger.cloudomation.com/api/latest/webhook/captain/call?mode=search&q=foo# the execution will receive in the input_value:# {"query": {"mode": "search", "q": "foo"}}
Configuration
Please see the table below for the different webhook fields and their meanings.
Field | Description |
---|---|
Flow | The flow which is started when the webhook is called |
Enabled | If unset, the HTTP endpoint is not available |
Is productive | If set, the executions are started in productive mode. See Development and Productive Mode. |
Require login token cookie | If set, the client has to provide a valid Cloudomation login token for the call to succeed. See Authentication. The execution will additionaly receive auth in the input_value containing information about the Cloudomation user. |
Key | An API key. If set, the client has to provide the API key for the call to succeed. The API key can be specified as a query parameter or as a key in a JSON payload. |
URL | A preview of the base URL of the webhook (Readonly) |
Public webhooks
A webhook can be considered public when it requires neither a login token nor an API key. For cloud workspaces, a public webhook can be called by anybody on the internet. For on-premise installations, public webhooks can be called by anybody who has network access to your Cloudomation workspace.
Private webhooks
A webhook can be considered private when it requires a login token and/or an API key.
Consider a webhook named "captain" in the workspace "jollyroger" which requires a login token.
# call without a token$ curl -i https://jollyroger.cloudomation.com/api/latest/webhook/captain/callHTTP/1.1 401 Unauthorized..."401 Unauthorized"# call with a token$ curl -i -H "x-cloudomation-token: ey..." https://jollyroger.cloudomation.com/api/latest/webhook/captain/callHTTP/1.1 200 OK
Consider a webhook named "captain" in the workspace "jollyroger" which requires an API key.
# call without API key$ curl -i https://jollyroger.cloudomation.com/api/latest/webhook/captain/callHTTP/1.1 401 Unauthorized# call with API key in the headers$ curl -i -H "Authorization: Bearer my-secret-key" https://jollyroger.cloudomation.com/api/latest/webhook/captain/callHTTP/1.1 200 OK# call with API key in query parameter$ curl -i https://jollyroger.cloudomation.com/api/latest/webhook/captain/call\?key=my-secret-keyHTTP/1.1 200 OK# when using a method which allows for a body payload# the API key can also be specified in the JSON body$ curl -i -H "Content-Type: application/json" -d '{"key": "my-secret-key"}' -X POST https://jollyroger.cloudomation.com/api/latest/webhook/captain/callHTTP/1.1 200 OK
Synchronous and asynchronous webhooks
Per default webhooks are called synchronously. The HTTP call will block until the execution reaches
the ENDED_SUCCESS
status. In synchronous mode the output_value of the execution will be returned to
the client in the response payload as JSON.
It is possible to call a webhook asynchronously by adding async
to the query parameters. In
asynchronous mode the HTTP response code will be 201 (Created) and the ID of the created execution
will be returned in the response body.
Consider a webhook named "captain" in the workspace "jollyroger".
# synchronous mode, the output_value is returned as JSON$ curl -i https://jollyroger.cloudomation.com/api/latest/webhook/captain/callHTTP/1.1 200 OKContent-Type: application/json; charset=utf-8...{"output": "value", "returned": "here"}# asynchronous mode, the execution ID is returned as plaintext$ curl -i https://jollyroger.cloudomation.com/api/latest/webhook/captain/call\?asyncHTTP/1.1 201 CreatedContent-Type: text/plain; charset=utf-8...aeae71f4-b062-4655-a333-d4d58014cf64
Error handling
When the execution does not end with ENDED_SUCCESS
Cloudomation will return the HTTP status 500
(Internal Server Error). The status and the status message of the execution will be returned in
the response body.
Consider a webhook named "captain" in the workspace "jollyroger".
$ curl -i https://jollyroger.cloudomation.com/api/latest/webhook/captain/callHTTP/1.1 500 Internal Server ErrorContent-Type: text/plain; charset=utf-8...ENDED_ERROR: status-message which was set by the execution
Custom responses
You can return custom responses from webhooks. There are three helper methods available:
Use of a custom response to perform a redirect
The helper webhook_response
allows for customization of status, headers, and body:
import flow_apidef handler(system: flow_api.System, this: flow_api.Execution):return this.webhook_response(status=302, # the HTTP status code to returnheaders={ # Additional HTTP headers to return'Location': 'https://cloudomation.com',},body='response-body', # The body payload to return)
The helper webhook_html_response
accepts a HTML string and will set the status to HTTP 200 and
content-type to text/html
:
Use of a custom HTML response
import randomimport flow_apidef handler(system: flow_api.System, this: flow_api.Execution):return this.webhook_html_response(body=(f'''<h1>Welcome to my homepage</h1><p>Rolling the dice: {random.randint(1,6)}</p><a href="call">roll again</a>'''),)
The helper webhook_json_response
accepts any object which can be JSON serialized and will set
the status to HTTP 200 and content-type to application/json
:
Use of a custom JSON response
import flow_apidef handler(system: flow_api.System, this: flow_api.Execution):return this.webhook_json_response(body={"some": ["nested","object",],},)
CRUD Example
The following is a simple flow script which implements a REST API for a food store. It shows how to read the path of the endpoint and return a custom body and HTTP status.
import jsonimport flow_apidef handler(system: flow_api.System, this: flow_api.Execution):input = this.get('input_value')storage_setting = system.setting("food store")try:storage_setting.get("value")except flow_api.exceptions.ResourceNotFoundError:storage_setting.save(value=[{"name": "apple","price": 1,},{"name": "banana","price": 2,},])storage_setting.acquire()storage = storage_setting.get("value")status = Nonebody = Noneif input['method'] == 'GET':if not input['path']:status = 200body = storageelse:for item in storage:if item["name"] == input["path"]:status = 200body = itembreakelif input["method"] == 'POST':item = {"name": input["json"]["name"],"price": input["json"]["price"],}storage.append([item])storage_setting.save(value=storage)body = itemstatus = 201elif input["method"] == 'DELETE':storage = [x for x in storage if x["name"] != input["path"]]storage_setting.save(value=storage)body = ""status = 200elif input["method"] == 'PATCH':for item in storage:if item["name"] == input["path"]:item["name"] = input["json"].get("name", item["name"])item["price"] = input["json"].get("price", item["price"])storage_setting.save(value=storage)body = itemstatus = 200breakreturn this.webhook_response(status=status,body=json.dumps(body),)
List all items in the food store
curl -X GET https://jollyroger.cloudomation.com/api/latest/webhook/food/call
[{"name": "banana", "price": 2}, {"name": "apple", "price": 1}]
Get the food with name "apple"
curl -X GET https://jollyroger.cloudomation.com/api/latest/webhook/food/call/apple
{"name": "apple", "price": 1}
Delete a food item.
curl -X DELETE https://jollyroger.cloudomation.com/api/latest/webhook/food/call/apple
Create a new food item
curl -X POST https://jollyroger.cloudomation.com/api/latest/webhook/food/call -d '{"name": "apple", "price": 2}' -H 'Content-Type: application/json'
{"name": "apple", "price": 2}
Update an existing item
curl -X PATCH https://jollyroger.cloudomation.com/api/latest/webhook/food/call/apple -d '{"price": 1}' -H 'Content-Type: application/json'
{"name": "apple", "price": 1}
ToDo App Example
A small ToDo web application implemented using a Cloudomation webhook can be found in the flow script library: