Skip to content

Formatting

Atomys edited this page Jun 30, 2023 · 9 revisions

Introduced in 0.6

One of the most useful bricks of Webhooked is perhaps this one. Formatting allows you to define the entire format of the data you will send to your storage. Globally or by storage.

Formatting use internally the go-template.

⚠ This is an advanced feature ⚠

Be careful when using this feature, the slightest error in format can result in DEFINITIVE loss of the collected data. Make sure your template is correct before applying it in production.

Configuration

You can activate and configure the formatting directly through the configuration file.

Formatting can be configured globally via the path .specs[].formatting or per storage via the path .specs[].storage[].formatting.

By default, if no formatting is present on your storage, Webhooked will take your global configuration. In case no formatting module is activated, the formatting applied is the body of the request ({{.Payload }})

You can configure your formatting in this way:

formatting:
  templatePath: /etc/config/webhooked/spec.tpl
  templateString: "{{ .Payload }}"
Path Type Description Default
formatting.templatePath string Path of the template file ''
formatting.templateString string Your template as string directly on the configuration file ''

NOTE: You can use one of the two fields. When templateString and templatePath are both configured, templateString takes the priority over templatePath

Variables

Certaines informations sont envoyer lors du rendu du template. Vous trouverez ci-dessous les données envoyés et accessible

Variable Type Description Note
.Request *http.Request Request of the received webhook.
.Payload string Body of the request serialized as string (called Payload)
.Spec *config.WebhookSpec Spec of the current webhook defined in the configuration Only the following field(s) are accessible :
Name, EntrypointURL
.Storage *config.StorageSpec Spec of the current storage defined in the configuration Only the following field(s) are accessible :
Type
.Config *config.Configuration Global configuration (reflection of your config file)

NOTE: Sensitive data such as webhook specifications and storage credentials are not accessible to protect your data.

Functions

Functions are utilities that you can use or not to make your template dynamic or extract data such as headers simply. As this module uses go-template, you have access to the functions of the package available here: go-template#Functions.

Function Return type Description Example
default interface{} Returns the default value if the given value is empty {{ nullableObject | default "defaultValue" }}
empty bool Returns true if the given value is empty {{ if empty "" }} -- block -- {{ end }}
coalesce interface{} Returns the first value not empty in the given list. {{ coalesce "", "awesome" }}
toJson string Returns the given value as a JSON string { "current_spec": {{ toJson .Spec }} }
fromJson map[string]interface{} Returns the given value as a Go map object { "payload": {{ fromJson(.Payload) }} }
toPrettyJson string Returns the given value as a pretty JSON string indented by two spaces { "current_spec": {{ toPrettyJson .Spec }} }
ternary interface{} Works as ternary condition in any language {{ condition | ternary "isTrue" "isFalse" }}
getHeader string Returns the value of the given header if present {{ .Request.Header | getHeader "X-Forwarded-For" }}
formatTime string Returns the given time formatted with the given format {{ .Now | formatTime "" "2006-01-02" }}
parseTime time.Time Returns the given time parsed with the given format {{ "2006-01-02" | parseTime "2006-01-02" }}
toString string Returns the given value as a string {{ 123 | toString }}
toInt int Returns the given value as an integer {{ "123" | toInt }}
toFloat float64 Returns the given value as a float {{ "123.45" | toFloat }}
toBool bool Returns the given value as a boolean {{ "true" | toBool }}
isNumber bool Returns true if the given value is a number {{ "123" | isNumber }}
isString bool Returns true if the given value is a string {{ "123" | isString }}
isBool bool Returns true if the given value is a boolean {{ "true" | isBool }}
isNull bool Returns true if the given value is null {{ null | isNull }}
add float64 Returns the sum of the given values {{ 1 | add 2 }}
sub float64 Returns the difference of the given values {{ 1 | sub 2 }}
mul float64 Returns the product of the given values {{ 1 | mul 2 }}
div float64 Returns the quotient of the given values {{ 1 | div 2 }}
mod float64 Returns the remainder of the given values {{ 1 | mod 2 }}
pow float64 Returns the power of the given values {{ 1 | pow 2 }}
max float64 Returns the maximum of the given values {{ 1 | max 2 }}
min float64 Returns the minimum of the given values {{ 1 | min 2 }}
sqrt float64 Returns the square root of the given value {{ 4 | sqrt }}

NOTE: interface{} mean you can give any type (string, int, float, complex, bool, ...) and have the same type in return

Example

Here is a concrete example that you can test at home via the webhooked binary

configuration file

apiVersion: v1alpha1
specs:
- name: demo
  entrypointUrl: /demo
  formatting:
    templateString: |
      {
        "specName": "{{ .Spec.Name }}",
        "metadata": {
          "contentType": "{{ .Request.Header | getHeader "Content-Type" }}",
          "deliveryID": "{{ .Request.Header | getHeader "X-Delivery" | default "unknown" }}"
        },
        "payload": {{ .Payload }}
      }
  storage: # { ... } Define your storage

Now you need to send a fake payload from webhook to webhooked with the following command

curl -H 'X-Delivery: b4b5970f-b57e-4b28-8f42-162a90a2651b' -XPOST 'http://127.0.0.1:8080/v1alpha1/demo' -d '{ "data": 123 }'

The data sent to your storage will correspond to your template in a sublime way

{
  "specName": "demo",
  "metadata": {
    "contentType": "application/x-www-form-urlencoded",
    "deliveryID": "b4b5970f-b57e-4b28-8f42-162a90a2651b"
  },
  "payload": { "data": 123 }
}