Skip to content

http_request component ​

The http_request component makes one outbound HTTP request and returns the response: status code, status line, headers, raw body, and the parsed JSON body under data when the response is JSON. It is a kdeps component from the components asset set: call it with a component: resource, no install step. Its call is the kdeps API's http_request tool, which runs the native HTTP executor. A workflow that uses httpClient: directly - primary or in a before:/after: step - is rejected.

It works in both modes: as a DAG step in workflow mode, and inside any workflow the LLM calls as a tool in agent mode.

component: http_requestPOST /tools/http_request/callkdeps API~/.kdeps/config.yamlhttp_connections / identity.accountsHTTP executorretry, cache, TLS, redirectsoutbound HTTP requestresult mapstatusCode, headers, body, dataconnectionName / accountName

Configuration ​

yaml
# resources/fetch.yaml
actionId: fetch
name: Fetch User
component:
  name: http_request               # from the components asset set; a components/http_request/ of your own wins
  with:
    method: GET                    # GET, POST, PUT, PATCH, DELETE (default GET)
    url: "https://api.example.com/users/{{ get('id') }}"
    headers:
      Accept: application/json
    data:                          # request body, serialized as JSON (POST, PUT, PATCH)
      name: "{{ get('name') }}"
    timeout: 30s                   # hard stop; returns an error, does not retry
    failOnError: false             # true: a 4xx/5xx fails the resource instead of returning a result
InputTypeRequiredDefaultDescription
urlstringyes-URL to request
methodstringnoGETGET, POST, PUT, PATCH, or DELETE
headersobjectno-Request headers as key-value pairs
dataobjectno-Request body, serialized as JSON
filesobjectno-Multipart form uploads: each key is a form field, each value a file path
timeoutstringnoexecutor defaultHard stop for the request, e.g. 30s
failOnErrorboolnofalseA non-2xx response becomes a resource error instead of a result
saveTostringno-Stream a 2xx body into this file; the result reports savedTo and bytes instead of the body
retryobjectno-{maxAttempts, backoff, maxBackoff, retryOn} - retry on the listed status codes
cacheobjectno-{ttl, key} - presence enables response caching, key defaults to the method and URL
connectionNamestringno-Named connection in ~/.kdeps/config.yaml supplying auth and proxy
accountNamestringno-Named account under the agent identity; resolved as Basic Auth
followRedirectsboolnofollowfalse stops at the first 3xx
tlsobjectno-{insecureSkipVerify, certFile, keyFile, caFile}

HTTP methods ​

yaml
# GET
component:
  name: http_request
  with:
    method: GET
    url: "https://api.example.com/users/{{ get('id') }}"

# POST with a JSON body
component:
  name: http_request
  with:
    method: POST
    url: "https://api.example.com/users"
    headers:
      Content-Type: application/json
    data:
      name: "{{ get('name') }}"
      email: "{{ get('email') }}"

# PUT
component:
  name: http_request
  with:
    method: PUT
    url: "https://api.example.com/users/{{ get('id') }}"
    data:
      name: "{{ get('name') }}"

# DELETE
component:
  name: http_request
  with:
    method: DELETE
    url: "https://api.example.com/users/{{ get('id') }}"

Authentication ​

Credentials belong in ~/.kdeps/config.yaml as named connections, not inline in resource files or workflow.yaml. The component references them with connectionName.

yaml
# ~/.kdeps/config.yaml
http_connections:
  stripe:
    auth:
      type: bearer
      token: "${STRIPE_SECRET_KEY}"
  internal-api:
    auth:
      type: basic
      username: "${API_USER}"
      password: "${API_PASS}"
  analytics:
    auth:
      type: api_key
      key: X-API-Key              # header name
      value: "${ANALYTICS_KEY}"
  oauth:
    auth:
      type: oauth2
      token: "${OAUTH2_ACCESS_TOKEN}"
  via-proxy:
    proxy: "http://${PROXY_USER}:${PROXY_PASS}@proxy.corp:8080"
    auth:
      type: bearer
      token: "${API_TOKEN}"
yaml
component:
  name: http_request
  with:
    method: GET
    url: "https://api.stripe.com/v1/charges"
    connectionName: stripe        # auth + proxy from http_connections.stripe

accountName is a lighter alternative for services the agent authenticates with as itself, using a named account from the agent's identity. It resolves as Basic Auth; when both are set, connectionName wins.

yaml
# ~/.kdeps/config.yaml
identity:
  accounts:
    crm:
      username: "${CRM_USER}"
      password: "${CRM_PASS}"
yaml
component:
  name: http_request
  with:
    method: GET
    url: "https://crm.example.com/contacts"
    accountName: crm

http_connections fields (in ~/.kdeps/config.yaml) ​

FieldTypeDescription
auth.typestringbasic, bearer, api_key, or oauth2
auth.usernamestringBasic auth username
auth.passwordstringBasic auth password
auth.tokenstringBearer / OAuth2 token
auth.keystringAPI key header name
auth.valuestringAPI key header value
proxystringProxy URL (may include user:pass@)

File upload, download and failing on errors ​

files: sends a multipart/form-data body: each key is a form field, each value the path of the file to upload; data: holds the text fields of the same form. saveTo: streams a 2xx response into a file instead of memory. failOnError: true turns a non-2xx response into a resource error instead of a result to inspect.

yaml
# resources/upload.yaml - multipart upload (e.g. a Whisper API)
component:
  name: http_request
  with:
    method: POST
    url: https://api.openai.com/v1/audio/transcriptions
    headers:
      Authorization: "Bearer {{ env('OPENAI_API_KEY') }}"
    files:
      file: "{{ get('audioPath') }}"   # field name -> file path, uploaded with its base name
    data:
      model: whisper-1                 # text fields of the same form
      language: "{{ get('lang') }}"
    failOnError: true                  # 4xx/5xx fails the resource with the status and body
yaml
# resources/download.yaml - fetch a file once
validations:
  skip:
    - "fileExists('/data/models/model.bin')"
component:
  name: http_request
  with:
    method: GET
    url: https://example.com/model.bin
    saveTo: /data/models/model.bin     # parent dirs created; written to .part then renamed
    timeout: 900s

With saveTo, the result is {statusCode, status, headers, savedTo, bytes} instead of body/data. A non-2xx response is not saved and comes back as a normal result, or an error with failOnError.

Retry ​

Retries use exponential backoff: attempt 1 immediately, then backoff, 2x backoff, up to maxBackoff.

yaml
component:
  name: http_request
  with:
    method: GET
    url: "https://api.example.com/data"
    retry:
      maxAttempts: 3          # total attempts, including the first
      backoff: 1s             # initial delay; doubles each retry
      maxBackoff: 30s         # ceiling on the delay
      retryOn: [429, 500, 502, 503, 504]   # status codes to retry

Response caching ​

Presence of the cache: block enables caching in the process memory store, shared across component calls.

yaml
component:
  name: http_request
  with:
    method: GET
    url: "https://api.example.com/static-data"
    cache:
      ttl: 5m                    # cache lifetime
      key: "static-data-cache"   # optional; defaults to the method and URL

TLS ​

yaml
# Skip certificate verification - development only
component:
  name: http_request
  with:
    method: GET
    url: "https://self-signed.example.com"
    tls:
      insecureSkipVerify: true

# Client certificates
component:
  name: http_request
  with:
    method: GET
    url: "https://internal.example.com"
    tls:
      certFile: "/certs/client.pem"
      keyFile: "/certs/client-key.pem"
      caFile: "/certs/ca.pem"

Redirects ​

Redirects are followed by default. Set followRedirects: false to stop at the first 3xx and return it as the result.

yaml
component:
  name: http_request
  with:
    method: GET
    url: "https://api.example.com/redirect"
    followRedirects: false

Output ​

json
{
  "statusCode": 200,
  "status": "200 OK",
  "headers": {"Content-Type": "application/json"},
  "body": "{\"name\":\"Ada\"}",
  "data": {"name": "Ada"}
}
KeyTypeDescription
statusCodeintegerHTTP status code
statusstringStatus line, e.g. 200 OK
headersobjectResponse headers
bodystringRaw response body
dataanyParsed body when it is JSON; absent otherwise
savedTostringFile the body was streamed into (saveTo)
bytesintegerBytes written (saveTo)

Read the parsed body with get('fetch').data, the status with get('fetch').statusCode.

Response accessors ​

Resource-specific accessors read the same result:

yaml
# resources/fetch.yaml runs first; this resource reads it
after:
  - set('response_body', http.responseBody('fetch'))            # body only
  - set('content_type', http.responseHeader('fetch', 'Content-Type'))
  - set('is_success', get('fetch').statusCode >= 200 && get('fetch').statusCode < 300)

See Unified API for details.

Error handling ​

Use preflight checks to validate before making requests:

yaml
validations:
  check:
    - get('user_id') != ''
  error:
    code: 400
    message: "user_id is required"

component:
  name: http_request
  with:
    method: GET
    url: "https://api.example.com/users/{{ get('user_id') }}"
    connectionName: myapi

See also ​

Released under the Apache 2.0 License.