Outbound HTTP in Actions
Use the nemoguardrails.http boundary for outbound HTTP requests from actions and library rails. It provides transport-neutral request, response, error, retry, and instrumentation contracts while keeping client ownership explicit.
Do not construct aiohttp, httpx, requests, or urllib3 clients inside an action. Direct transports bypass shared ownership, retry, testing, and observability policy.
Send a Request From an Action
Accept an optional HTTPClient and call http_call:
http_call raises HTTPStatusError for responses with status code 400 or greater by default. Pass raise_for_status=False only when the integration must inspect an error response and apply provider-specific behavior.
Client Ownership
The client argument determines ownership for each call:
The None fallback is safe and deterministic. Inject a shared client for applications that make repeated requests and benefit from connection-pool reuse.
Manifest-driven IORails owns one shared pooled client, passes it to every rail action that declares http_client, and closes it when the runtime stops. Other applications can use the same lifecycle pattern. The action signature is the injection contract; rail manifests do not declare whether the runtime should allocate a transport.
Create and close a shared client at the same application lifecycle boundary:
The synchronous config.py initialization hook has no asynchronous teardown hook. Do not create a long-lived HTTP client there unless another application component owns and closes it.
Request and Response Contract
HTTPClient.request and http_call support:
- HTTP method and absolute URL.
- Headers and query parameters.
- A JSON body, raw string content, or raw byte content.
- A per-request total timeout.
They return a materialized HTTPResponse. Its body bytes remain available after a call-scoped client closes.
HTTPResponse.json() raises HTTPResponseDecodeError for invalid JSON. HTTPResponse.raise_for_status() and http_call raise HTTPStatusError for status codes of 400 or greater.
The canonical error hierarchy is:
HTTPClientErrorHTTPConnectionErrorHTTPTimeoutErrorHTTPStatusErrorHTTPResponseDecodeError
Catch the narrowest error that the integration can handle without changing its intended fail-open or fail-closed behavior. Do not log response bodies, request bodies, credentials, or unsanitized exception details.
Configure the Pooled Transport
create_http_client creates a closable HTTPX-backed client behind the neutral protocol. The default client:
- Uses a 30-second total timeout.
- Verifies TLS certificates.
- Does not follow redirects.
- Pools up to 100 connections, including up to 20 keep-alive connections.
Override these policies explicitly when an integration requires different behavior:
HTTPTLSConfig also supports a client certificate and key for mutual TLS. Configure both together. Keep certificate verification enabled in production.
Add Bounded Retries
Requests are not retried unless the client has a RetryPolicy. max_attempts includes the initial request.
The default policy retries eligible connection and timeout failures and the status codes 408, 409, 429, 500, 502, 503, and 504. It uses bounded exponential backoff with jitter and accepts Retry-After values within the configured limit.
The safe default method set excludes POST. Add POST only when the provider documents the operation as retry-safe or the request uses a supported idempotency mechanism:
The retryable_methods argument replaces the default set. This example preserves the default methods and adds POST.
Keep retry policy close to the integration that owns the provider semantics. Do not add a broad global POST retry policy.
Add Privacy-Safe Instrumentation
Wrap a shared client with instrument_http_client to enable tracing, metrics, or both:
Wrap the retrying client, as shown above, to record one span and one duration observation for the logical request rather than one per retry attempt.
Tracing emits a CLIENT span named HTTP {METHOD}. Metrics emit the http.client.request.duration histogram. Telemetry can include:
- Method, URL scheme, server address, and port.
- A sanitized URL without credentials, query parameters, or fragments.
- Raw request-body size when
contentis used. - Response status and body size.
- Retry count and error type.
Instrumentation does not record header values, query values, JSON bodies, raw body content, credentials, response content, or exception messages. Telemetry failures do not change the request result.
Instrumentation is explicit at this boundary. Creating an HTTP client without instrument_http_client does not enable HTTP spans or metrics automatically. The component that creates the instrumented client must also close it.
For the emitted names and attributes, refer to Span Reference and Metric Reference.
Test Without Network Access
Use RecordingHTTPClient to queue responses and inspect the exact provider request:
Queue transport errors and non-success responses to verify retry, timeout, decoding, and fail-open or fail-closed behavior. Unit tests must not call a live provider.
For configuration-level testing patterns, refer to Testing Your Guardrails Configuration.