http-request
Calls another URL from the policy — an auth service, a feature flag, an internal endpoint — so later rules can act on the answer.
| Phases | on_http_requeston_http_response |
| Terminating | No — the next action runs after it. |
| Cost | 1 Traffic Policy unit per run · not on the Free plan |
Example
on_http_request:
- actions:
- type: http-request
config:
url: https://auth.example.com/check
method: POST
headers:
content-type: application/json
body: '{"path": "${req.url.path}", "ip": "${conn.client_ip}"}'
timeout: 2s
retry_condition: "last_attempt.res.status_code >= 500"
- expressions:
- "actions.ngrok.http_request.res.status_code != 200"
actions:
- type: deny
config:
status_code: 403
Start an agent endpoint with it: devgate http 8080 --traffic-policy-file policy.yaml, or paste it into a
reserved or cloud endpoint’s Traffic Policy tab in the dashboard.
Configuration
| Field | Type | Description |
|---|---|---|
url required | string | A public http(s) URL, or one of your internal endpoints (https://name.internal/path). May use ${…}. |
method | string | GET, PUT, POST, PATCH, DELETE or OPTIONS. Default: GET. |
headers | map | Up to 10 request headers. Values may use ${…}. |
query_params | list of {key, value} | Up to 32 query parameters added to the URL. Values may use ${…}. |
body | string | The request body, e.g. JSON for a POST. May use ${…}. |
timeout | duration | The longest the whole action may take, retries and redirects included: 1s to 30s. Default: 3s. |
max_redirects | integer | Redirects to follow, 0 to 100. With 0 the 3xx answer itself is the result. Default: 0. |
retry_condition | expression | A CEL expression checked after each attempt; when true the call is made again, up to 3 more times. It sees attempts, last_attempt.req, last_attempt.res and last_attempt.error. |
on_error | string | continue moves on when the call fails; halt answers the visitor 502 and stops the policy. Default: continue. |
Result variables
After it runs, later rules can read what it decided:
-
actions.ngrok.http_request.res— The last answer: status_code, header (lowercase names, values as lists), body, resolved_ip and time_ms. -
actions.ngrok.http_request.req— What was sent: method, url, header and body. -
actions.ngrok.http_request.attempts— One entry per attempt: response_status_code, response_header, response_time_ms, resolved_ip. -
actions.ngrok.http_request.error.code / error.message— Why the call failed, e.g. timeout or forbidden_address; empty when it didn’t.
Behaviour
- The answer isn’t sent to the visitor: later rules read it in actions.ngrok.http_request.* and decide.
- For safety devgate never calls private networks, loopback (127.0.0.1, localhost), link-local addresses or cloud metadata (169.254.169.254) — checked when it connects, after DNS, and on every redirect.
- An internal endpoint is reached through its agent; its own Traffic Policy doesn’t run for these calls.
- The answer is read up to 256 KB; a bigger one fails the call (response_too_large).
- A timeout, a refused connection, a blocked address or too many redirects sets error.code and error.message; with on_error: halt the visitor gets 502 and nothing after the action runs.
- Each call carries User-Agent devgate-traffic-policy/1.0, X-Forwarded-For with the visitor’s IP and devgate-req-type: http-request (header names are case-insensitive). Calls nested more than 3 deep are refused, so endpoints calling each other can’t loop.
- Retries wait 100, 200 and 400 ms. A call costs 1 unit however many attempts it takes.
Other actions
add-headers remove-headers compress-response basic-auth oauth openid-connect jwt-validation custom-response deny redirect url-rewrite restrict-ips rate-limit circuit-breaker verify-webhook set-vars log close-connection forward-internal