pub trait HttpExecutor: Send + Sync {
// Required method
fn execute_request<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
method: &'life1 str,
path: ResolvedPath<'life2>,
body: Option<Value>,
) -> Pin<Box<dyn Future<Output = Result<Value, ExecutionError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait;
// Provided method
fn placeholder_rules(
&self,
method: &str,
path_template: &str,
param: &str,
) -> PlaceholderRules<'_> { ... }
}Expand description
Trait for making HTTP requests during execution.
This abstraction allows the executor to be used with different HTTP clients and enables easy testing with mock implementations.
§The D-09 contract change (Phase 128)
execute_request’s path parameter used to be a bare &str carrying the
TEMPLATE the script wrote, and each implementor resolved its own {key}
placeholders inside its own impl. That made the public trait a blind seam: a
decorator wrapping HttpExecutor to inspect outbound requests saw only the
template and never the values, so a placeholder carrying a query separator
became a different endpoint with nothing in a position to notice.
Resolution now happens in PlanExecutor BEFORE dispatch, and the parameter
is a ResolvedPath rather than a &str so the change is a compile error
for a stale implementor instead of a silent semantic shift. A stale
implementor that kept compiling would quietly double-resolve an
already-resolved path, which for a security fix is the worst available
outcome.
Required Methods§
Sourcefn execute_request<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
method: &'life1 str,
path: ResolvedPath<'life2>,
body: Option<Value>,
) -> Pin<Box<dyn Future<Output = Result<Value, ExecutionError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn execute_request<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
method: &'life1 str,
path: ResolvedPath<'life2>,
body: Option<Value>,
) -> Pin<Box<dyn Future<Output = Result<Value, ExecutionError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Execute an HTTP request.
path is already fully resolved and checked — see ResolvedPath. Do
NOT perform placeholder substitution here; body has already had the
path-consumed keys removed.
Provided Methods§
Sourcefn placeholder_rules(
&self,
method: &str,
path_template: &str,
param: &str,
) -> PlaceholderRules<'_>
fn placeholder_rules( &self, method: &str, path_template: &str, param: &str, ) -> PlaceholderRules<'_>
The placeholder rules to apply to one LAYER-2 {param} value.
This is the D4(b) seam on the Code Mode surface. PlanExecutor has no
access to an OpenAPI document; the only component that does is the
executor implementation, so the narrowing has to be asked for here.
method is part of the signature and not decoration: an OpenAPI schema
indexes operations by (path, METHOD), so GET /things/{id} and
DELETE /things/{id} are two operations that may declare different
constraints for the same id. A (path_template, param) signature could
not disambiguate them and would have to either scan linearly or narrow
from the wrong operation.
path_template is the path as it reaches layer 2 — after layer-1
${var} interpolation and before {key} substitution. For the ordinary
case of a string-literal path that is byte-identical to the OpenAPI path
template, which is what makes a spec lookup work.
§The default is safe
The default returns PlaceholderRules::default(),
which is FLOOR-PLUS-CAP-WITH-NO-NARROWING. An implementor that keeps the
default still gets the unconditional character floor and the always-on
256-code-point cap on every value; what is absent is only the
spec-declared narrowing. The floor is never what a missing override costs.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".