Formatting

Templates are powerful. Use them wisely to transform your webhook data exactly as needed.

Introduction

Webhooked uses Go templates enhanced with 100+ functions from go-sprout to transform webhook data. This powerful templating system allows you to reshape, validate, and enrich data before storage or in responses.

Template Functions

Webhooked use internally go-template for functionality and sprout to provide 100+ functions.

Full documentation of sprout are available here : Sprout

Template String

For simple template or a desire to have all configuration inside the yaml file, you can put your tempalte directly inline

formatting:
  templateString: |
    {{- with $data := fromJSON .Payload -}}
    {{- $timestamp := $data.created_at | toDate "2006-01-02T15:04:05Z07:00" | unixEpoch -}}
    {
      "id": "{{ $data.id }}",
      "created": "{{ $timestamp }}",
      "reference": "{{ $data.id }}-{{ $timestamp }}"
    }
    {{- end -}}

Template Files

For complex templates, usage of external files are recommended

formatting:
  templatePath: /config/templates/webhook-transform.tmpl

Template file (webhook-transform.tmpl):

{{- /* Complex webhook transformation template */ -}}
{{- $data := fromJSON .Payload -}}
{{- $config := dict 
  "environment" (env "ENVIRONMENT")
  "version" (env "VERSION")
  "region" (env "REGION")
-}}
{
  "metadata": {{ $config | toJSON }},
  "payload": {{ $data | toJSON }},
  "processed": "{{ now }}"
}

Best Practices

  1. Always parse JSON once and reuse the result

  2. Use with blocks for nil-safety

  3. Provide defaults for optional fields

  4. Use external files for complex templates

  5. Cache computed values in variables

  6. Document complex logic with comments

  7. Test templates with various payloads

Performance Optimization

Parse Once, use multiple times

GOOD: Parse one

formatting:
  templateString: |
    {{ with $data := fromJSON .Payload }}
      ID: {{ $data.id }}
      Type: {{ $data.type }}
      User: {{ $data.user_id }}
    {{ end }}

BAD: Parse multiple times

formatting:
  templateString: |
    ID: {{ (fromJSON .Payload).id }}
    Type: {{ (fromJSON .Payload).type }}
    User: {{ (fromJSON .Payload).user_id }}

Avoid Unnecessary Operations

GOOD: Cache computed values

formatting:
  templateString: |
    {{ $timestamp := now }}
    {{ $id := uuidv4 }}
    {{ with $data := fromJSON .Payload }}
      {
        "id": "{{ $id }}",
        "created": "{{ $timestamp }}",
        "modified": "{{ $timestamp }}",
        "reference": "{{ $id }}-{{ $timestamp | unixEpoch }}"
      }
    {{ end }}

BAD: Recall functions multiples times can cause bug and latency

formatting:
  templateString: |
    {{ with $data := fromJSON .Payload }}
      {
        "id": "{{ uuidv4 }}",
        "created": "{{ now }}",
        "modified": "{{ now }}",
        "reference": "{{ uuidv4 }}-{{ now | unixEpoch }}"
      }
    {{ end }}

Avoid String building

GOOD: Use template engine

formatting:
  templateString: |
    {{ with $data := fromJSON .Payload }}
      {{ $data.type }}:{{ $data.id }}:{{ $data.timestamp }}
    {{ end }}

BAD: use go functions to build end strings

formatting:
  templateString: |
    {{ with $data := fromJSON .Payload }}
      {{ printf "%s:%s:%d" $data.type $data.id $data.timestamp }}
    {{ end }}

This is provided as example, printf function aren't available on sprout project

Common Issues and Solutions

Issue: Template Syntax Errors

# Error: unexpected "}" in operand
formatting:
  templateString: '{{ .Value }'  # Missing closing brace

# Fixed:
formatting:
  templateString: '{{ .Value }}'

Issue: JSON Escaping

# Problem: Invalid JSON output
formatting:
  templateString: '{"message": "{{ .Message }}"}'

# Solution: Use toJSON for proper escaping
formatting:
  templateString: '{"message": {{ .Message | toJSON }}}'

Issue: Nil Pointer

# Problem: Accessing non-existent field
formatting:
  templateString: '{{ $data.user.uame }}'

# Solution: Safe navigation using dig and default
formatting:
  templateString: |
    {{ $data | dig "user.uame" | default "Unknown" }}

Last updated