pub struct ApiCall { /* private fields */ }
Expand description
Builder for configuring HTTP API calls with comprehensive parameter and validation support.
ApiCall
provides a fluent interface for building HTTP requests with automatic OpenAPI schema collection.
It supports query parameters, headers, request bodies, and flexible status code validation.
§Method Groups
§Request Body Methods
json(data)
- Set JSON request bodyform(data)
- Set form-encoded request bodymultipart(form)
- Set multipart form request bodytext(content)
- Set plain text request bodyraw(bytes)
- Set raw binary request body
§Parameter Methods
with_query(query)
- Set query parameterswith_headers(headers)
- Set request headerswith_header(name, value)
- Add single header
§Status Code Validation
with_expected_status_codes(codes)
- Set expected status codeswith_status_range_inclusive(range)
- Set inclusive range (200..=299)with_status_range(range)
- Set exclusive range (200..300)add_expected_status(code)
- Add single expected statusadd_expected_status_range_inclusive(range)
- Add inclusive rangeadd_expected_status_range(range)
- Add exclusive rangewith_client_errors()
- Accept 2xx and 4xx codes
§OpenAPI Metadata
with_operation_id(id)
- Set operation IDwith_tags(tags)
- Set operation tags (or use automatic tagging)with_description(desc)
- Set operation description (or use automatic description)
§Response Descriptions
with_response_description(desc)
- Set description for the actual returned status code
§Execution
.await
- Execute the request and return response (⚠️ must consume result for OpenAPI)
§Default Behavior
- Status codes: Accepts 200-499 (inclusive of 200, exclusive of 500)
- Content-Type: Automatically set based on body type
- Schema collection: Request/response schemas are automatically captured
- Operation metadata: Automatically generated if not explicitly set
§Automatic OpenAPI Metadata Generation
When you don’t explicitly set operation metadata, ApiCall
automatically generates:
§Automatic Tags
Tags are extracted from the request path using intelligent parsing:
Path: /api/v1/users/{id} → Tags: ["users"]
Path: /users → Tags: ["users"]
Path: /users/export → Tags: ["users", "export"]
Path: /observations/import → Tags: ["observations", "import"]
Path Prefix Skipping: Common API prefixes are automatically skipped:
api
,v1
,v2
,v3
,rest
,service
(and more)/api/v1/users
becomes["users"]
, not["api", "v1", "users"]
Special Action Detection: Certain path segments get their own tags:
import
,upload
,export
,search
,bulk
/users/export
→["users", "export"]
§Automatic Descriptions
Descriptions are generated based on HTTP method and path:
GET /users → "Retrieve users"
GET /users/{id} → "Retrieve user by ID"
POST /users → "Create user"
PUT /users/{id} → "Update user by ID"
DELETE /users/{id} → "Delete user by ID"
§Automatic Operation IDs
Generated from HTTP method and path: "get-users-id"
, "post-users"
, etc.
You can override any of these by calling the corresponding with_*
methods.
Implementations§
Source§impl ApiCall
impl ApiCall
pub fn with_operation_id(self, operation_id: impl Into<String>) -> Self
Sourcepub fn with_description(self, description: impl Into<String>) -> Self
pub fn with_description(self, description: impl Into<String>) -> Self
Sets the operation description for OpenAPI documentation.
§Examples
let mut client = ApiClient::builder().build()?;
let call = client.get("/users")?.with_description("Retrieve all users");
Sets the operation tags for OpenAPI categorization.
§Examples
let mut client = ApiClient::builder().build()?;
let call = client.get("/users")?.with_tags(vec!["users", "admin"]);
// Also works with arrays, slices, or any IntoIterator
let call = client.get("/users")?.with_tags(["users", "admin"]);
Sourcepub fn with_tag(self, tag: impl Into<String>) -> Self
pub fn with_tag(self, tag: impl Into<String>) -> Self
Adds a single tag to the operation for OpenAPI categorization.
§Examples
let mut client = ApiClient::builder().build()?;
let call = client.get("/users")?.with_tag("users").with_tag("admin");
Sourcepub fn with_response_description(self, description: impl Into<String>) -> Self
pub fn with_response_description(self, description: impl Into<String>) -> Self
Sets a response description for the actual returned status code.
This method allows you to document what the response means for your API endpoint. The description will be applied to whatever status code is actually returned by the server and included in the generated OpenAPI specification.
§Examples
let mut client = ApiClient::builder().build()?;
let call = client.get("/users/{id}")?
.with_response_description("User details if found, or error information");
Sourcepub fn without_collection(self) -> Self
pub fn without_collection(self) -> Self
Excludes this API call from OpenAPI collection and documentation generation.
When called, this API call will be executed normally but will not appear in the generated OpenAPI specification. This is useful for:
- Health check endpoints
- Debug/diagnostic endpoints
- Authentication/session management calls
- Test setup/teardown calls
- Internal utility endpoints
- Administrative endpoints not part of public API
§Examples
let mut client = ApiClient::builder().build()?;
// Health check that won't appear in OpenAPI spec
client
.get("/health")?
.without_collection()
.await?
.as_empty()
.await?;
// Debug endpoint excluded from documentation
client
.get("/debug/status")?
.without_collection()
.await?
.as_text()
.await?;
pub fn with_query(self, query: CallQuery) -> Self
pub fn with_headers_option(self, headers: Option<CallHeaders>) -> Self
Sourcepub fn with_headers(self, headers: CallHeaders) -> Self
pub fn with_headers(self, headers: CallHeaders) -> Self
Adds headers to the API call, merging with any existing headers.
This is a convenience method that automatically wraps the headers in Some().
Sourcepub fn with_header<T: ParameterValue>(
self,
name: impl Into<String>,
value: impl Into<ParamValue<T>>,
) -> Self
pub fn with_header<T: ParameterValue>( self, name: impl Into<String>, value: impl Into<ParamValue<T>>, ) -> Self
Convenience method to add a single header.
This method automatically handles type conversion and merges with existing headers. If a header with the same name already exists, the new value will override it.
§Examples
§Basic Usage
let mut client = ApiClient::builder().build()?;
let call = client.get("/users")?
.with_header("Authorization", "Bearer token123")
.with_header("X-Request-ID", "abc-123-def");
§Type Flexibility and Edge Cases
let mut client = ApiClient::builder().build()?;
// Different value types are automatically converted
let call = client.post("/api/data")?
.with_header("Content-Length", 1024_u64) // Numeric values
.with_header("X-Retry-Count", 3_u32) // Different numeric types
.with_header("X-Debug", true) // Boolean values
.with_header("X-Session-ID", "session-123"); // String values
// Headers can be chained and overridden
let call = client.get("/protected")?
.with_header("Authorization", "Bearer old-token")
.with_header("Authorization", "Bearer new-token"); // Overrides previous value
Adds cookies to the API call, merging with any existing cookies.
This method accepts a CallCookies
instance and merges it with any existing
cookies on the request. Cookies are sent in the HTTP Cookie header and can
be used for session management, authentication, and storing user preferences.
§Examples
let mut client = ApiClient::builder().build()?;
let cookies = CallCookies::new()
.add_cookie("session_id", "abc123")
.add_cookie("user_id", 456);
let call = client.get("/dashboard")?
.with_cookies(cookies);
Convenience method to add a single cookie.
This method automatically handles type conversion and merges with existing cookies. If a cookie with the same name already exists, the new value will override it.
§Examples
§Basic Usage
let mut client = ApiClient::builder().build()?;
let call = client.get("/dashboard")?
.with_cookie("session_id", "abc123")
.with_cookie("user_id", 456);
§Type Flexibility and Edge Cases
let mut client = ApiClient::builder().build()?;
// Different value types are automatically converted
let call = client.get("/preferences")?
.with_cookie("theme", "dark") // String values
.with_cookie("user_id", 12345_u64) // Numeric values
.with_cookie("is_premium", true) // Boolean values
.with_cookie("selected_tags", vec!["rust", "web"]); // Array values
// Cookies can be chained and overridden
let call = client.get("/profile")?
.with_cookie("session_id", "old-session")
.with_cookie("session_id", "new-session"); // Overrides previous value
Sourcepub fn with_authentication(self, authentication: Authentication) -> Self
pub fn with_authentication(self, authentication: Authentication) -> Self
Overrides the authentication for this specific request.
This method allows you to use different authentication for a specific request, overriding the default authentication configured on the API client.
§Examples
use clawspec_core::{ApiClient, Authentication};
// Client with default authentication
let mut client = ApiClient::builder()
.with_authentication(Authentication::Bearer("default-token".into()))
.build()?;
// Use different authentication for a specific request
let response = client
.get("/admin/users")?
.with_authentication(Authentication::Bearer("admin-token".into()))
.await?;
// Remove authentication for a public endpoint
let response = client
.get("/public/health")?
.with_authentication_none()
.await?;
Sourcepub fn with_authentication_none(self) -> Self
pub fn with_authentication_none(self) -> Self
Removes authentication for this specific request.
This is useful when making requests to public endpoints that don’t require authentication, even when the client has default authentication configured.
§Examples
use clawspec_core::{ApiClient, Authentication};
// Client with default authentication
let mut client = ApiClient::builder()
.with_authentication(Authentication::Bearer("token".into()))
.build()?;
// Remove authentication for public endpoint
let response = client
.get("/public/status")?
.with_authentication_none()
.await?;
Sourcepub fn with_status_range_inclusive(self, range: RangeInclusive<u16>) -> Self
pub fn with_status_range_inclusive(self, range: RangeInclusive<u16>) -> Self
Sets the expected status codes for this request using an inclusive range.
By default, status codes 200..500 are considered successful. Use this method to customize which status codes should be accepted.
§Examples
§Basic Usage
let mut client = ApiClient::builder().build()?;
// Accept only 200 to 201 (inclusive)
let call = client.post("/users")?.with_status_range_inclusive(200..=201);
// Accept any 2xx status code
let call = client.get("/users")?.with_status_range_inclusive(200..=299);
§Edge Cases
let mut client = ApiClient::builder().build()?;
// Single status code range (equivalent to with_expected_status)
let call = client.get("/health")?.with_status_range_inclusive(200..=200);
// Accept both success and client error ranges
let call = client.delete("/users/123")?
.with_status_range_inclusive(200..=299)
.add_expected_status_range_inclusive(400..=404);
// Handle APIs that return 2xx or 3xx for different success states
let call = client.post("/async-operation")?.with_status_range_inclusive(200..=302);
Sourcepub fn with_status_range(self, range: Range<u16>) -> Self
pub fn with_status_range(self, range: Range<u16>) -> Self
Sets the expected status codes for this request using an exclusive range.
§Examples
let mut client = ApiClient::builder().build()?;
// Accept 200 to 299 (200 included, 300 excluded)
let call = client.get("/users")?.with_status_range(200..300);
Sourcepub fn with_expected_status(self, status: u16) -> Self
pub fn with_expected_status(self, status: u16) -> Self
Sets a single expected status code for this request.
§Examples
let mut client = ApiClient::builder().build()?;
// Accept only 204 for DELETE operations
let call = client.delete("/users/123")?.with_expected_status(204);
Sourcepub fn add_expected_status(self, status: u16) -> Self
pub fn add_expected_status(self, status: u16) -> Self
Adds an additional expected status code to the existing set.
§Examples
let mut client = ApiClient::builder().build()?;
// Accept 200..299 and also 404
let call = client.get("/users")?.with_status_range_inclusive(200..=299).add_expected_status(404);
Sourcepub fn add_expected_status_range_inclusive(
self,
range: RangeInclusive<u16>,
) -> Self
pub fn add_expected_status_range_inclusive( self, range: RangeInclusive<u16>, ) -> Self
Adds an additional expected status range (inclusive) to the existing set.
§Examples
let mut client = ApiClient::builder().build()?;
// Accept 200..=204 and also 400..=402
let call = client.post("/users")?.with_status_range_inclusive(200..=204).add_expected_status_range_inclusive(400..=402);
Sourcepub fn add_expected_status_range(self, range: Range<u16>) -> Self
pub fn add_expected_status_range(self, range: Range<u16>) -> Self
Adds an additional expected status range (exclusive) to the existing set.
§Examples
let mut client = ApiClient::builder().build()?;
// Accept 200..=204 and also 400..403
let call = client.post("/users")?.with_status_range_inclusive(200..=204).add_expected_status_range(400..403);
Sourcepub fn with_success_only(self) -> Self
pub fn with_success_only(self) -> Self
Convenience method to accept only 2xx status codes (200..300).
§Examples
let mut client = ApiClient::builder().build()?;
let call = client.get("/users")?.with_success_only();
Sourcepub fn with_client_errors(self) -> Self
pub fn with_client_errors(self) -> Self
Convenience method to accept 2xx and 4xx status codes (200..500, excluding 3xx).
§Examples
let mut client = ApiClient::builder().build()?;
let call = client.post("/users")?.with_client_errors();
Sourcepub fn with_expected_status_codes(self, codes: ExpectedStatusCodes) -> Self
pub fn with_expected_status_codes(self, codes: ExpectedStatusCodes) -> Self
Sets the expected status codes using an ExpectedStatusCodes
instance.
This method allows you to pass pre-configured ExpectedStatusCodes
instances,
which is particularly useful with the expected_status_codes!
macro.
§Examples
use clawspec_core::{ApiClient, expected_status_codes};
let mut client = ApiClient::builder().build()?;
// Using the macro with with_expected_status_codes
let call = client.get("/users")?
.with_expected_status_codes(expected_status_codes!(200-299));
// Using manually created ExpectedStatusCodes
let codes = clawspec_core::ExpectedStatusCodes::from_inclusive_range(200..=204)
.add_expected_status(404);
let call = client.get("/items")?.with_expected_status_codes(codes);
Sourcepub fn with_expected_status_code(self, status: StatusCode) -> Self
pub fn with_expected_status_code(self, status: StatusCode) -> Self
Sets expected status codes from a single http::StatusCode
.
This method provides compile-time validation of status codes through the type system.
Unlike the u16
variants, this method does not perform runtime validation since
http::StatusCode
guarantees valid HTTP status codes at compile time.
§Example
use clawspec_core::ApiClient;
use http::StatusCode;
let mut client = ApiClient::builder().build()?;
let call = client.get("/users")?
.with_expected_status_code(StatusCode::OK);
Sourcepub fn with_expected_status_code_range(
self,
range: RangeInclusive<StatusCode>,
) -> Self
pub fn with_expected_status_code_range( self, range: RangeInclusive<StatusCode>, ) -> Self
Sets expected status codes from a range of http::StatusCode
.
This method provides compile-time validation of status codes through the type system.
Unlike the u16
variants, this method does not perform runtime validation since
http::StatusCode
guarantees valid HTTP status codes at compile time.
§Example
use clawspec_core::ApiClient;
use http::StatusCode;
let mut client = ApiClient::builder().build()?;
let call = client.get("/users")?
.with_expected_status_code_range(StatusCode::OK..=StatusCode::NO_CONTENT);
Sourcepub fn json<T>(self, t: &T) -> Result<Self, ApiClientError>
pub fn json<T>(self, t: &T) -> Result<Self, ApiClientError>
Sets the request body to JSON.
This method serializes the provided data as JSON and sets the
Content-Type header to application/json
.
§Examples
#[derive(Serialize, ToSchema)]
struct CreateUser {
name: String,
email: String,
}
let mut client = ApiClient::builder().build()?;
let user_data = CreateUser {
name: "John Doe".to_string(),
email: "john@example.com".to_string(),
};
let call = client.post("/users")?.json(&user_data)?;
Sourcepub fn form<T>(self, t: &T) -> Result<Self, ApiClientError>
pub fn form<T>(self, t: &T) -> Result<Self, ApiClientError>
Sets the request body to form-encoded data.
This method serializes the provided data as application/x-www-form-urlencoded
and sets the appropriate Content-Type header.
§Examples
#[derive(Serialize, ToSchema)]
struct LoginForm {
username: String,
password: String,
}
let mut client = ApiClient::builder().build()?;
let form_data = LoginForm {
username: "user@example.com".to_string(),
password: "secret".to_string(),
};
let call = client.post("/login")?.form(&form_data)?;
Sourcepub fn raw(self, data: Vec<u8>, content_type: ContentType) -> Self
pub fn raw(self, data: Vec<u8>, content_type: ContentType) -> Self
Sets the request body to raw binary data with a custom content type.
This method allows you to send arbitrary binary data with a specified content type. This is useful for sending data that doesn’t fit into the standard JSON or form categories.
§Examples
let mut client = ApiClient::builder().build()?;
// Send XML data
let xml_data = r#"<?xml version="1.0"?><user><name>John</name></user>"#;
let call = client.post("/import")?
.raw(xml_data.as_bytes().to_vec(), ContentType::xml());
// Send binary file
let binary_data = vec![0xFF, 0xFE, 0xFD];
let call = client.post("/upload")?
.raw(binary_data, ContentType::octet_stream());
Sourcepub fn text(self, text: &str) -> Self
pub fn text(self, text: &str) -> Self
Sets the request body to plain text.
This is a convenience method for sending plain text data with
text/plain
content type.
§Examples
let mut client = ApiClient::builder().build()?;
let call = client.post("/notes")?.text("This is a plain text note");
Sourcepub fn multipart(self, parts: Vec<(&str, &str)>) -> Self
pub fn multipart(self, parts: Vec<(&str, &str)>) -> Self
Sets the request body to multipart/form-data.
This method creates a multipart body with a generated boundary and supports both text fields and file uploads. This is commonly used for file uploads or when combining different types of data in a single request.
§Examples
let mut client = ApiClient::builder().build()?;
let parts = vec![
("title", "My Document"),
("file", "file content here"),
];
let call = client.post("/upload")?.multipart(parts);
Trait Implementations§
Source§impl IntoFuture for ApiCall
Implement IntoFuture for ApiCall to enable direct .await syntax
impl IntoFuture for ApiCall
Implement IntoFuture for ApiCall to enable direct .await syntax
This provides a more ergonomic API by allowing direct .await
on ApiCall:
let response = client.get("/users")?.await?;