http-request/MODULE.md
flemming-it 4681d0bb2c feat: http.request v0.1.0 — generic HTTP client
First release. Pure-WASM HTTP client built on waki 0.5 for
F∆I flow steps that need to call REST APIs.

Capability: http.request@0.1.0

Inputs: method (GET/POST/PUT/PATCH/DELETE/HEAD/OPTIONS),
url, headers (JSON object string), body (UTF-8).

Outputs: status (decimal text), headers (JSON object), body
(UTF-8 lossy).

Permissions: net: *. The wildcard is deliberate — operators
clamp to specific hosts via their operator-policy ceiling.

6 unit tests on the headers-input parser (empty / strings /
numbers coerced / non-object rejected / nested rejected /
malformed JSON rejected).

Bundle: target/wasm32-wasip2/release/http_request.wasm
(~120 KiB stripped).

v0.2.0 candidates: http.request-bytes for binary payloads,
per-request timeout / retry inputs, cookie-jar.

Signed-off-by: flemming-it <sf@flemming.it>
2026-05-25 14:16:09 +02:00

93 lines
2.9 KiB
Markdown

# http.request
Generic HTTP client for flow steps. GET / POST / PUT / PATCH /
DELETE / HEAD / OPTIONS with arbitrary headers and a UTF-8
body. The audit-friendly alternative to flows rolling their
own HTTP clients.
## Capability
- `http.request@0.1.0`
## Inputs
| Name | Type | Description |
| --------- | ---- | --------------------------------------------------------------------------------- |
| `method` | text | Uppercase HTTP verb (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`). |
| `url` | text | Full URL including scheme. |
| `headers` | text | Optional JSON-object string of extra headers. Empty = none. |
| `body` | text | Optional UTF-8 request body. Empty = no body. |
Example `headers` input:
```json
{"Accept":"application/json","X-Tenant":"acme","Content-Length":42}
```
String, numeric, and boolean values are accepted (numbers and
bools are coerced to strings). Nested arrays / objects are
rejected at parse time with a clear error.
## Outputs
| Name | Type | Description |
| --------- | ---- | -------------------------------------------------------------------- |
| `status` | text | Decimal status code as text (e.g. `"200"`, `"404"`). |
| `headers` | text | Response headers serialised as a JSON object (lowercased keys). |
| `body` | text | Response body as UTF-8. Replacement chars on non-UTF-8. |
Status is text rather than number so the audit-log entry stays
operator-readable without JSON re-parsing.
## Permissions
```yaml
permissions:
- "net: *"
```
The wildcard makes it explicit that this module can call any
HTTP endpoint by design. Operators clamp the surface in their
policy ceiling (`~/.fai/config.yaml#security.max_permissions.net`)
— installing http.request against a policy that disallows
wildcards fails at install time.
## Why a generic primitive instead of per-API modules
Same answer as `llm.chat`: a single explicit egress module
means operators audit `net: *` exactly once, not in every flow
YAML. The permission posture stays observable.
## Limits in v0.1.0
- UTF-8 body only. Binary upload / download is a separate
`http.request-bytes` capability (v0.2.0).
- No per-request timeout / retry inputs (waki's default
timeouts apply).
- No cookie-jar or session-keeping inputs.
## Example flow
```yaml
name: post-to-webhook
inputs:
payload: text
steps:
- id: notify
use: http.request@^0
with:
method: "POST"
url: "https://example.org/webhook"
headers: '{"Content-Type":"application/json"}'
body: $inputs.payload
outputs:
status: $notify.status
echo: $notify.body
```
## Build
```bash
cargo build --release --target wasm32-wasip2
# Output: target/wasm32-wasip2/release/http_request.wasm
```