Documentation
¶
Overview ¶
Package rest integrates an external HTTP-REST API as a service-task connector: a BPMN REST connector task calls a model-authored endpoint through the job path (ADR-0036/0067), mirroring how the dmn package delegates a decision to temis (ADR-0014). The integration inherits the job protocol's durability and non-blocking properties (ADR-0007):
- A connector task creates a job carrying the reserved compiler.RestJobType. The processor never performs the outbound call itself, so it stays allocation-free (invariant I1) and free of any HTTP dependency.
- The in-process Handler — a job worker — pulls those jobs, calls the REST API off the processor goroutine and after fsync (invariant I2, never inside applyToState / I4), writes the JSON response into the task's result variable, and completes the job, which drives the token onward.
Unlike the clio connector (ADR-0036), a REST task authors its full URL, method, headers, and query parameters in the model; credentials are never authored there — authentication (basic/bearer/apiKey) names a server-side secret the worker resolves at runtime (ADR-0041/0067), so a token never appears in a BPMN file.
Delivery is at-least-once (a crash between "the API accepted the call" and "job completed" replays the request); every request carries the job key as an Idempotency-Key header so a well-behaved API de-duplicates a replayed non-idempotent request rather than performing it twice.
Index ¶
- func Handler(store state.Reader, lookup ProcessLookup, client Client, secret SecretResolver, ...) job.OutputHandler
- func NewTokenProvider() *tokenProvider
- type Client
- type HTTPClient
- type Job
- type OAuthConfig
- type ProcessLookup
- type Request
- type Response
- type Result
- type SecretResolver
- type TokenProvider
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Handler ¶
func Handler(store state.Reader, lookup ProcessLookup, client Client, secret SecretResolver, tokens TokenProvider) job.OutputHandler
Handler builds a job handler that performs an HTTP-REST connector task. Register it with a job.Runner under the reserved compiler.RestJobTypeIndex via HandleWithOutput; the runner then pulls activatable REST jobs, and for each the handler resolves the connector task's method/url/headers/query/result-variable from the compiled process and calls the API through client — evaluating any FEEL url/header/query values over the variables the task sees, up its scope chain (the fx toggle, ADR-0067/0068), and sending as the JSON request body, for methods that carry one, what the task's input mappings map — or, with none, every variable it sees (ADR-0174) — keyed by the job key so an at-least-once retry de-duplicates. Authentication (basic/bearer/apiKey) is resolved through secret, which turns the model's secret *reference* into the credential at call time (ADR-0041); the token never lives in the model. When the task names a result variable, the JSON response is returned as that variable to be written back into the instance on completion. Returning an error fails the job (retry, then an incident, ADR-0061); the runner completes it only on success.
func NewTokenProvider ¶ added in v0.3.0
func NewTokenProvider() *tokenProvider
NewTokenProvider builds a token provider bounded by the shared connector call budget (nettimeout.HTTPClient), like the REST client itself.
Types ¶
type Client ¶
Client calls a REST API. It is an interface so the worker is testable without a live server.
type HTTPClient ¶
type HTTPClient struct {
// contains filtered or unexported fields
}
HTTPClient calls a real REST API over HTTP. It sends Request.Body as a JSON body (when present) to Request.URL with an Idempotency-Key header, and decodes a JSON response body. A non-2xx status is returned as an error so the job stays pending and is retried (at-least-once).
func NewHTTPClient ¶
func NewHTTPClient() *HTTPClient
NewHTTPClient builds a REST HTTP client bounded by the shared connector call budget (nettimeout.Default). The worker runs on the run-loop goroutine, so an unbounded call would let a hung host stall the whole engine; see the nettimeout package doc. A per-connector configurable timeout is a follow-up (ADR-0067).
type Job ¶ added in v0.3.0
type Job struct {
Method string `json:"method"`
URL string `json:"url"`
Headers map[string]string `json:"headers,omitempty"`
Query map[string]string `json:"query,omitempty"`
Body map[string]any `json:"body,omitempty"`
// Auth is the authored auth configuration, encoded as it sits in the compiled
// process. It names a secret; it never carries one (see [compiler.RestAuth]).
Auth string `json:"auth,omitempty"`
// IdempotencyKey is the job key, so a call retried after a lease elapsed is
// recognizable to the far end as the same one.
IdempotencyKey string `json:"idempotencyKey,omitempty"`
// Result names the process variable the response is written to; empty means the
// model discards it.
Result string `json:"resultVariable,omitempty"`
}
Job is a REST task with everything model-authored already evaluated. It is what travels with a leased job, and it has nowhere to put a secret.
func Resolve ¶ added in v0.3.0
func Resolve(store state.Reader, cp *compiler.CompiledProcess, detail *compiler.ConnectorTaskDetail, ei *model.ElementInstanceValue, elementInstanceKey, jobKey uint64) (Job, error)
Resolve turns a compiled REST task into a Job. Engine work by necessity: FEEL is compiled at deploy (ADR-0008/0015) and the scope lives in the store.
Auth is deliberately left unapplied. Applying it here would mean resolving the secret here, and then the credential would be in the job — which is the one thing the split exists to prevent.
type OAuthConfig ¶ added in v0.3.0
OAuthConfig identifies one OAuth2 client-credentials token request (ADR-0152). TokenURL is the token endpoint; ClientID/ClientSecret authenticate the client; Scope is the optional space-delimited scope list. ClientSecret is the resolved value (from a secret reference, ADR-0041), never a reference here.
type ProcessLookup ¶
type ProcessLookup func(defKey uint64) *compiler.CompiledProcess
ProcessLookup resolves a process-definition key to its compiled process. The worker uses it to find the method, URL, and result variable a REST job belongs to, so one handler serves every deployed process.
type Request ¶
type Request struct {
Method string
URL string
Headers map[string]string
Query map[string]string
Body map[string]any
IdempotencyKey string
}
Request is one HTTP call a REST connector task makes. URL is the full, model-authored endpoint (ADR-0067). Headers are set on the request (including any Authorization/api-key header the worker resolved from a secret); Query is appended to the URL. Body, when non-nil, is sent as a JSON request body (the worker attaches it only for methods that carry one). IdempotencyKey is deterministic (the job key), so an at-least-once retry can be de-duplicated by the target API.
type Response ¶
Response is a REST call's outcome. Status is the HTTP status code; Body is the decoded JSON response (an object, array, number, string, bool or nil), or the raw response text when it is not valid JSON.
type Result ¶ added in v0.3.0
Result is what calling a Job produces.
func Run ¶ added in v0.3.0
func Run(ctx context.Context, j Job, client Client, secret SecretResolver, tokens TokenProvider) (Result, error)
Run applies the caller's own credential to a resolved job and makes the call. The in-process path calls it too, so there is one definition of what a resolved REST task means rather than two that drift — only whose secret store is in reach differs.
type SecretResolver ¶
SecretResolver returns the secret value for a reference name, or "" if unknown. The worker uses it to turn a REST task's authentication secret *reference* into the actual credential at call time (ADR-0041), so a token never lives in the model or the compiled process — only its reference does.
type TokenProvider ¶ added in v0.3.0
type TokenProvider interface {
Token(ctx context.Context, cfg OAuthConfig) (string, error)
}
TokenProvider fetches an OAuth2 access token for a client-credentials grant. It is an interface so the worker is testable without a live token endpoint.