Skip to main content

@hile/http-over-micro

Preserve HTTP method, headers, status, JSON bodies, and binary streams across Registry-discovered Hile Micro calls.

Choose This Package When

Use When

Use this package when one HTTP ingress must project a request to a Registry-discovered Hile microservice while preserving HTTP method, duplicate headers, query values, status, cookies, redirects, JSON bodies, and streamed file bodies. The package defines the transport contract only. The public listener and its authentication, authorization, route selection, header policy, and final Koa response remain owned by the gateway.

Do Not Use When

  • Do not use it for ordinary in-process HTTP controllers that do not cross a Micro boundary.
  • Do not use it as a durable queue or retry layer.
  • Do not use it for RSC Flight, MCP, WebSocket upgrades, HTTP trailers, or informational 1xx responses; those protocols keep their own transports.
  • Do not put business logic in the gateway merely because the gateway performs the HTTP projection.

Install

Imports

Copy-Paste Example

Provider message:
Gateway-side call:
Pass only gateway-approved end-to-end request headers. The sample assumes a body parser has already produced ctx.request.body; use the untouched incoming Readable instead for raw uploads.

More Examples

Upload and download without a transport switch

The caller supplies a normal JSON value or an AsyncIterable, Uint8Array, or ArrayBuffer. callHttpOverMicro() snapshots JSON values into the request envelope and automatically moves binary or iterable bodies into Micro request input.
Provider:
Every HOM call defaults to retries: 0, including reads, writes, inline bodies, and streams. Streaming request bodies are non-replayable: an explicit nonzero value fails before dispatch. Opt-in retry of replayable requests still needs an end-to-end attempt budget and business idempotency; failure does not prove that a write did not commit. The adapter never retries a malformed response after consuming its head/body.

Response metadata before response bytes

Every HTTP-over-Micro call uses one Micro response stream. Its first chunk is a response head; body chunks follow only when body.kind is stream:
Header tuples deliberately preserve order and duplicate fields such as Set-Cookie. Header names are canonical lowercase on the wire. Query tuples preserve repeated query values without inventing an object serialization rule.

Zod parses, not merely checks

schema.headers, schema.query, schema.params, and schema.body each receive the logical value seen by the handler. Schema transforms and coercions are returned to the handler. For a streamed request, schema.body receives the Readable. Use a Zod custom or union schema only when that endpoint intentionally accepts a stream; a JSON-object body schema rejects the stream naturally.

Runtime And Lifecycle Notes

  • defineHttpOverMicroMessage() returns a defineMicroMessage() definition marked with protocol: '@hile/http-over-micro'. File loading preserves this marker; raw app.register(path, definition.fn, { protocol: definition.protocol }) must pass it explicitly.
  • callHttpOverMicro() fixes the outgoing protocol marker; callers cannot override it. Micro carries that marker in existing request metadata and rejects a route/protocol mismatch after route matching but before any handler/schema/business side effect. Plain Micro routes cannot become HOM routes by receiving a payload that resembles its HTTP envelope. The reverse misdelivery is rejected too, and a mismatch does not fall through to a less-specific route.
  • The marker is protocol isolation, not authentication or capability authorization. There is no new modem frame, operation addressing mode, dispatcher endpoint, or parallel discovery catalog. The optional metadata field is an incremental wire value: all selectable receiver replicas must be upgraded before relying on isolation, because older receivers may ignore it.
  • The Micro route remains the file/message path. HTTP method is protocol data and one definition may accept one method or a method list. Unsupported methods return 405 plus Allow without invoking the handler.
  • Inline bodies use JSON serialization semantics and default to a 1 MiB bound. Override limits.maxInlineBodyBytes explicitly on both ends when a deployment requires another limit; use streams for files and large byte bodies.
  • Final response statuses are 200..599. HEAD, 204, 205, and 304 responses reject bodies. 1xx, protocol upgrades, and trailers are intentionally out of scope.
  • Destroying the returned streamed body cancels the underlying Micro response. signal, total timeout, idle timeout, and stream window are passed to Application.stream().
  • Credit-based backpressure bounds buffered chunks, not the total number of transferred bytes. The HTTP ingress and provider handler must each enforce their endpoint-specific upload/download byte limit while consuming a stream.
  • The caller owns the returned response stream and must consume or destroy it. The package fully consumes empty and inline responses before resolving.
  • Cookies and Location are opaque response headers. The public gateway remains responsible for cookie ownership, security attributes, redirect policy, and hop-by-hop header removal.
  • Treat namespace and url as public routing information, not authorization. Gateway owns external authentication and policy; an owning service exposes an HTTP adapter by explicitly defining its HOM message. Use normal Micro discovery and route protocol isolation, not a new Browser provider catalog. Deployments allowing client-selected service namespaces must evaluate that routing exposure explicitly; the marker does not prevent direct calls by trusted internal peers.

Anti-Patterns

  • Do not handcraft the request envelope or consume the response-head frame yourself; use callHttpOverMicro().
  • Do not call Application.call() for this protocol. A response may need headers followed by a body stream, so the package intentionally uses Application.stream() for every result.
  • Do not encode files as Base64 inside an inline JSON body.
  • Do not collapse response headers into a plain object when duplicate Set-Cookie values matter.
  • Do not enable retries for an upload stream.
  • Do not expose ordinary Micro handlers through a public route merely because their input schema happens to reject an HOM envelope; require the pre-handler protocol check on every selectable replica.
  • Do not create an additional business dispatcher, generated HTTP route table, or MCP capability catalog to wrap typed Micro operations.
  • Do not forward every inbound header, raw cookie, or identity credential merely because the protocol can carry it.

Verification Checklist

  • Unit tests cover inline, empty, malformed, method-mismatch, and Zod-coercion cases.
  • A real Registry-discovered WebSocket test carries request and response streams at the same time.
  • Duplicate response headers survive in order.
  • Invalid request metadata fails with HTTP status 400; invalid upstream response metadata fails locally with 502.
  • Inline bodies are bounded and JSON-serializable; files use stream bodies.
  • Cancellation, timeout, idle timeout, and backpressure remain owned by @hile/micro and @hile/message-modem.
  • Real Registry/WebSocket tests cover ordinary-to-HOM and HOM-to-ordinary misdelivery with zero handler effects, including file-loaded marker preservation and explicit raw registration.
  • Same-service delegation uses the explicit local unary binding; native streamed business operations retain their native interfaces and must not be forced through the unary contract.

Micro RPC With Message Loader

Complete Example

Provider handler:
Untyped dynamic handlers may use a required catch-all when the operation is intentionally not a typed Micro Contract:
Typed Micro Contract operation.path values stay fixed and cannot use [id] or [...paths]. Provider boot:
Consumer:

Package-Local AI Guide

This package also ships AI.md in npm so agents can read accurate examples after installation.