Skip to main content

External API Calls from Workflows

Overview

The web_request action lets customers wire their workflows into external systems. A typical use is checking a loyalty point balance in the customer's own CRM, storing the returned value as a user attribute, and then sending a message containing it.

This work runs under its own profile (SVC=web-request-worker) because the destination is a customer-operated API that may be slow or down, and it must not be allowed to drag down the main action queue.

Business Flow

  1. Receive the same ActionExecutePayload used by action_execute, but with actionType = web_request.
  2. Read WebRequestActionConfig from actionConfig: method, url, headers, body, responseMappings, postAction, and the retry and timeout settings.
  3. Resolve merge tags in the url, headers, and body. The {{...}} syntax draws from three sources:
    • system attributes, via systemattribute.Service, which caches them in Redis
    • line_user fields and custom_attribute values
    • the userId directly
  4. Fire the HTTP request with retries
    • the default timeout is 30,000 ms (defaultTimeoutMs)
    • up to three attempts (defaultRetryMaxAttempts), with backoff starting at 1,000 ms
    • errors are classified explicitly: clientError for 4xx responses, which are not retried, and serverError for 5xx responses, which are retried and expose StatusCode() so the mq layer can treat them as transient
  5. Map the response back through processResponseMappings, where each mapping uses JSONPath to extract a value from the response and write it to a destination.
    • destinations can be a system attribute or a user attribute (line_user.custom_attribute)
    • the {{value}} template is supported for composing new values
    • a single failing mapping does not fail the whole job
  6. postAction — when configured, a new ActionExecutePayload is assembled and published to action_execute to continue the chain, for instance sending a message containing the points just retrieved. This is how workflows are chained together.
  7. onError — if the configuration defines an error branch, that path is taken instead.

Key Files & Functions

  • internal/webrequest/service.go
    • Service.Execute(ctx, payload) — the entry point, with execute() holding the real flow
    • executeWithRetry(), doRequest(), onError()
    • processResponseMappings(), processOneMapping()
    • resolveMergeTags(), resolveHeaderMergeTags(), getLineUser()
    • the error types clientError, serverError (which has a StatusCode() method), and statusError
    • the constants defaultTimeoutMs = 30000, defaultRetryMaxAttempts = 3, and defaultRetryBackoffMs = 1000
  • internal/webrequest/consumer.goConsumer.HandleWebRequest
  • internal/webrequest/config.go — the WebRequestActionConfig and ResponseMapping structs
  • internal/webrequest/jsonpath.go — the JSONPath implementation, matching the jsonpath-plus behaviour of the legacy system
  • internal/systemattribute/systemattribute.go — reads and writes system attributes, cached in Redis
  • cmd/worker/main.gorunWebRequestWorker()
  • Queue: consumes web_request_execute and publishes action_execute (profile web-request-worker)

Connections to Other Services

  • Receives jobs from: the Trigger / Workflow Automation Engine, whose executeAction routes to this queue whenever rule.actionType equals web_request
  • Tables: line_user (both as a merge tag source and as the write target for custom_attribute), plus system_attribute and attribute_master
  • Redis: the system attribute cache
  • External HTTP: the customer's API, using the method, url, and headers from the configuration
  • RabbitMQ: publishes to action_execute for postAction
  • This job never calls the LINE API directly — message delivery happens in the postAction, via the action executor