iii-http
Expose registered functions as HTTP endpoints via an `http` trigger, with a preHandler middleware chain for auth, rate limiting, and logging. Reach for it to serve REST without standing up a separate web server.
What this skill does
# iii-http
The `iii-http` worker exposes registered functions as HTTP endpoints. It runs an HTTP server on the configured host/port, matches each inbound request against the `http` triggers you bind, and invokes the bound function with the request. The handler returns a response envelope that the worker serializes to the wire — JSON, plain text, or bytes, depending on the `Content-Type` the handler sets.
The worker has no callable functions of its own — you never invoke an `http::*` id. Its surface is the `http` trigger TYPE plus a middleware chain that runs before each handler. You expose an endpoint by registering a normal function and binding an `http` trigger to it.
## Do NOT stand up your own web server
This is the way to serve HTTP on iii, and the only one: register a function, then bind an `http` trigger to it. Do NOT write or run your own web server — no `express`, no `http.createServer`, no `fastify`, no framework listening on a port. iii does not route to a server you start yourself; such a process is unreachable as an iii endpoint, and running it as a foreground process (e.g. inside a sandbox) just hangs. If you are reaching for a web framework or a `listen()` call, stop — that instinct is from another ecosystem. The iii equivalent is one `iii.registerTrigger({ type: 'http', ... })` per route; this worker is the server.
## Get the contract from the engine
This page explains WHEN and HOW to serve HTTP; the engine is the source of truth for the exact shapes. Before you bind a trigger or write a handler, fetch the contract and build to it — do not guess field names, types, or defaults from memory:
```
engine::triggers::info { id: "http" }
```
returns three schemas: `configuration_schema` (the route fields — path, method, optional route gating, per-route middleware), `request_schema` (the request envelope your handler receives), and `response_schema` (the response envelope your handler must return). Build to all three. Use `engine::triggers::list` to discover trigger types in the first place.
## Set the right HTTP status
YOUR handler chooses the HTTP status code — it is a field on the response envelope whose exact name is in the `response_schema` from `engine::triggers::info { id: "http" }` (read it; do not guess the field name from memory). The status is NOT inferred from the body, so a handler that just returns a value or an error object yields `200` by default. For error cases, set the matching status explicitly: a not-found path returns `404`, a bad request `400`, and so on. Returning `200` with an `{ error: ... }` body is a bug — it "isn't a 500," but it also isn't the status the requirement asked for, and callers (and tests) will read it as success. Avoiding a crash is not the same as returning the right status.
## When to Use
- Expose a function as a REST endpoint without standing up a separate HTTP server.
- You need URL path parameters or query strings parsed and handed to the handler.
- You want condition-gated routes or per-route preHandler middleware.
- You need a single not-found handler for unmatched routes.
## Boundaries
- No callable functions — the worker is never reached through an `http::*` id; routes are bound with `iii.registerTrigger`, not called.
- Two routes on the same path + method conflict; the router resolves to the most recently registered one.
- Query-string parsing is single-valued — a repeated key keeps only the last value; pre-encode multi-valued params yourself.
- Middleware runs BEFORE body parsing, so it sees headers, path, and query but not the body — use it for preconditions, not response logic (that belongs in the handler).
## Binding a route
Register your handler as a normal function, then bind an `http` trigger to it with `iii.registerTrigger` using the `http` trigger type. Shape the trigger config to what `engine::triggers::info { id: "http" }` describes — the route path and method, an optional gating function evaluated before the handler, and per-route middleware. Path segments you declare in the route arrive as string path parameters on the request; the gating function, if set, can veto a request before the handler runs.
## Where your route is served
Your bound route is served by the `iii-http` worker on its configured host and port — NOT on a port you pick. The default port is `3111` (host `0.0.0.0`), so a route with path `/example` is reachable at `http://localhost:3111/example` on a default deployment. Do NOT guess other ports (3000, 8080, the engine's WS port): if the deployment overrides the default, read the live host/port from the `iii-http` worker's configuration (`config.yaml`) or its status rather than probing. Verify a live endpoint with `web::fetch` against that base URL, never `curl`.
## Middleware
Register a middleware function when the same logic must run before multiple routes — authentication, rate limiting, request logging, header normalization. A middleware is a regular registered function that receives a subset of the request (without the body) and either lets the request proceed (optionally enriching its context) or short-circuits with an immediate response. Target middleware two ways:
- Globally — via the worker's middleware config in `config.yaml`; runs on every matched route, in priority order.
- Per-route — via the trigger's middleware list; runs after the global chain, in the order given.
The full preHandler order per request: route match → global middleware → route gating function → per-route middleware → body parsing → handler.
## Configuration
The worker is configured in `config.yaml`: the listen host and port, request timeout, concurrency and body-size limits, proxy trust and request-id header, trailing-slash handling, a not-found handler function, CORS, and the global middleware chain. For the full set of keys and their defaults, read the worker's configuration rather than hardcoding values from memory.
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.