Expand description
§Clawspec Core
Generate OpenAPI specifications from your HTTP client test code.
This crate provides two main ways to generate OpenAPI documentation:
ApiClient- Direct HTTP client for fine-grained controlTestClient- Test server integration with automatic lifecycle management
New to Clawspec? Start with the Tutorial for a step-by-step guide.
§Quick Start
§Using ApiClient directly
use clawspec_core::ApiClient;
let mut client = ApiClient::builder()
.with_host("api.example.com")
.build()?;
// Make requests - schemas are captured automatically
let user: User = client
.get("/users/123")?
.await? // ← Direct await using IntoFuture
.as_json() // ← Important: Must consume result for OpenAPI generation!
.await?;
// Generate OpenAPI specification
let spec = client.collected_openapi().await;§Using TestClient with a test server
For a complete working example, see the axum example.
use clawspec_core::test_client::{TestClient, TestServer};
use std::net::TcpListener;
#[tokio::test]
async fn test_api() -> Result<(), Box<dyn std::error::Error>> {
let mut client = TestClient::start(MyServer).await?;
// Test your API
let response = client.get("/users")?.await?.as_json::<serde_json::Value>().await?;
// Write OpenAPI spec
client.write_openapi("api.yml").await?;
Ok(())
}§Working with Parameters
use clawspec_core::{ApiClient, CallPath, CallQuery, CallHeaders, CallCookies, ParamValue, ParamStyle};
// Path parameters
let path = CallPath::from("/users/{id}")
.add_param("id", ParamValue::new(123));
// Query parameters
let query = CallQuery::new()
.add_param("page", ParamValue::new(1))
.add_param("limit", ParamValue::new(10));
// Headers
let headers = CallHeaders::new()
.add_header("Authorization", "Bearer token");
// Cookies
let cookies = CallCookies::new()
.add_cookie("session_id", "abc123")
.add_cookie("user_id", 456);
// Direct await with parameters:
let response = client
.get(path)?
.with_query(query)
.with_headers(headers)
.with_cookies(cookies)
.await?; // Direct await using IntoFuture§Parameter Styles
The library supports OpenAPI 3.1.0 parameter styles. Use ParamStyle for advanced serialization:
use clawspec_core::{CallPath, CallQuery, ParamValue, ParamStyle};
// Path: simple (default), label, matrix
let path = CallPath::from("/users/{id}").add_param("id", ParamValue::new(123));
// Query: form (default), spaceDelimited, pipeDelimited, deepObject
let query = CallQuery::new()
.add_param("tags", ParamValue::with_style(vec!["a", "b"], ParamStyle::PipeDelimited));See Chapter 4: Advanced Parameters for detailed examples.
§Authentication
Configure authentication at the client or per-request level:
use clawspec_core::{ApiClient, Authentication};
let mut client = ApiClient::builder()
.with_host("api.example.com")
.with_authentication(Authentication::Bearer("token".into()))
.build()?;
// Override per-request
client.get("/admin")?.with_authentication(Authentication::Bearer("admin-token".into())).await?;Supported types: Bearer, Basic, ApiKey. See Chapter 4 for details.
§Status Code Validation
By default, requests expect status codes in the range 200-499 (inclusive of 200, exclusive of 500). You can customize this behavior:
use clawspec_core::{ApiClient, expected_status_codes};
// Single codes
client.post("/users")?
.with_expected_status_codes(expected_status_codes!(201, 202))
.await?;
// Ranges
client.get("/health")?
.with_expected_status_codes(expected_status_codes!(200-299))
.await?;§Response Descriptions
Add descriptive text to your OpenAPI responses for better documentation:
use clawspec_core::ApiClient;
// Set a description for the actual returned status code
client.get("/users/{id}")?
.with_response_description("User details if found, or error information")
.await?;
// The description applies to whatever status code is actually returned
client.post("/users")?
.with_response_description("User created successfully or validation error")
.await?;§Response Redaction
Requires the redaction feature.
When generating OpenAPI examples from real API responses, dynamic values like UUIDs, timestamps, and tokens make examples unstable across test runs. The redaction feature allows you to replace these dynamic values with stable, predictable ones in the generated OpenAPI specification while preserving the actual values for assertions.
This is particularly useful for:
- Snapshot testing: Generated OpenAPI files remain stable across runs
- Documentation: Examples show consistent, readable placeholder values
- Security: Sensitive values can be masked in documentation
§Basic Usage
use clawspec_core::ApiClient;
#[derive(Deserialize, ToSchema)]
struct User {
id: String, // Dynamic UUID
name: String,
created_at: String, // Dynamic timestamp
}
let user: User = client
.post("/users")?
.json(&serde_json::json!({"name": "Alice"}))?
.await?
.as_json_redacted()
.await?
// Replace dynamic UUID with stable value
.redact("/id", "00000000-0000-0000-0000-000000000001")?
// Replace timestamp with stable value
.redact("/created_at", "2024-01-01T00:00:00Z")?
.finish()
.await
.value;
// The actual user has real dynamic values for assertions
assert!(!user.id.is_empty());
// But the OpenAPI example shows the redacted stable values§Redaction Operations
The redaction builder supports two operations using JSON Pointer (RFC 6901):
redact(pointer, redactor): Replace a value at the given path with a stable value or transformationredact_remove(pointer): Remove a value entirely from the OpenAPI example
let response: Response = client
.post("/auth/login")?
.json(&serde_json::json!({"username": "test", "password": "secret"}))?
.await?
.as_json_redacted()
.await?
.redact("/token", "[REDACTED_TOKEN]")?
.redact("/session_id", "session-00000000")?
.redact_remove("/internal_ref")? // Remove internal field from docs
.finish()
.await
.value;§Path Syntax
Paths are auto-detected based on their prefix:
/...→ JSON Pointer (RFC 6901) - exact paths only$...→ JSONPath (RFC 9535) - supports wildcards
§JSON Pointer Syntax
JSON Pointers use / as a path separator. Special characters are escaped:
~0represents~~1represents/
Examples:
/id- Top-level field named “id”/user/name- Nested field “name” inside “user”/items/0/id- First element’s “id” in an array/foo~1bar- Field named “foo/bar”
§JSONPath Wildcards
For arrays, use JSONPath syntax (starting with $) to redact all elements:
let users: Vec<User> = client
.get("/users")?
.await?
.as_json_redacted()
.await?
.redact("$[*].id", "stable-uuid")? // All IDs in array
.redact("$[*].created_at", "2024-01-01T00:00:00Z")? // All timestamps
.finish()
.await
.value;§Dynamic Transformations
Pass a closure for dynamic redaction. The closure receives the concrete JSON Pointer path and current value:
let users: Vec<User> = client
.get("/users")?
.await?
.as_json_redacted()
.await?
// Create stable index-based IDs: user-0, user-1, user-2, ...
.redact("$[*].id", |path: &str, _val: &Value| {
let idx = path.split('/').nth(1).unwrap_or("0");
serde_json::json!(format!("user-{idx}"))
})?
.finish()
.await
.value;§Getting Both Values
The RedactedResult returned by finish() contains both:
value: The actual deserialized response (with real dynamic values)redacted: The JSON with redacted values (as stored in OpenAPI)
let result = client
.get("/users/123")?
.await?
.as_json_redacted::<User>()
.await?
.redact("/id", "user-00000000")?
.finish()
.await;
// Use actual value for test assertions
let user = result.value;
assert!(!user.id.is_empty());
// Access redacted JSON if needed
let redacted_json = result.redacted;
assert_eq!(redacted_json["id"], "user-00000000");§Schema Registration
Schemas are automatically captured when using .json() and .as_json() methods.
For nested schemas or error types, use register_schemas!:
use clawspec_core::{ApiClient, register_schemas};
register_schemas!(client, Address, ErrorResponse).await;Note: Nested schemas may not be fully resolved automatically. Register them explicitly if they’re missing from your OpenAPI output.
§Error Handling
The library provides two main error types:
ApiClientError- HTTP client errors (network, parsing, validation)TestAppError- Test server lifecycle errors
§YAML Serialization
Requires the yaml feature.
The library provides YAML serialization support using serde-saphyr,
the modern replacement for the deprecated serde_yaml crate.
use clawspec_core::{ApiClient, ToYaml};
let mut client = ApiClient::builder()
.with_host("api.example.com")
.build()?;
// ... make API calls ...
let spec = client.collected_openapi().await;
let yaml = spec.to_yaml()?;
std::fs::write("openapi.yml", yaml)?;§See Also
ApiClient- HTTP client with OpenAPI collectionApiCall- Request builder with parameter supporttest_client- Test server integration moduleExpectedStatusCodes- Status code validationRedactionBuilder- Builder for redacting response values in OpenAPI examplesRedactedResult- Result containing both actual and redacted valuesRedactOptions- Options for configuring redaction behaviorRedactor- Trait for types that can be used to redact valuesredact_value- Entry point for redacting arbitrary JSON valuesValueRedactionBuilder- Builder for redacting arbitrary JSON values (e.g., OpenAPI specs)ToYaml- Extension trait for YAML serializationYamlError- Error type for YAML serialization
§Re-exports
All commonly used types are re-exported from the crate root for convenience.
Modules§
- _tutorial
- Tutorial: Getting Started with Clawspec
- split
- OpenAPI specification splitting utilities.
- test_
client - Generic test client framework for async server testing.
Macros§
- expected_
status_ codes - Creates an
ExpectedStatusCodesinstance with the specified status codes and ranges. - register_
schemas - Registers multiple schema types with the ApiClient for OpenAPI documentation.
Structs§
- ApiCall
- Builder for configuring HTTP API calls with comprehensive parameter and validation support.
- ApiClient
- ApiClient
Builder - Builder for creating
ApiClientinstances with comprehensive configuration options. - Call
Body - Represents the body of an HTTP request with its content type and schema information.
- Call
Cookies - Represents HTTP cookies for an API call.
- Call
Headers - Represents HTTP headers for an API call.
- Call
Path - A parameterized HTTP path with type-safe parameter substitution.
- Call
Query - A collection of query parameters for HTTP requests with OpenAPI 3.1 support.
- Call
Result - Represents the result of an API call with response processing capabilities.
- Expected
Status Codes - Expected status codes for HTTP requests.
- Info
- OpenAPI types re-exported from utoipa for convenience. OpenAPI Info object represents metadata of the API.
- Info
Builder - OpenAPI types re-exported from utoipa for convenience.
Builder for
Infowith chainable configuration methods to create a newInfo. - OAuth2
Config oauth2 - OAuth2 authentication configuration.
- OAuth2
Config Builder oauth2 - Builder for OAuth2 configuration.
- OAuth2
Flow - OAuth2 flow configuration (for flows with token URL).
- OAuth2
Flows - OAuth2 flow configurations.
- OAuth2
Implicit Flow - OAuth2 implicit flow configuration.
- OAuth2
Token oauth2 - An OAuth2 access token with expiration tracking.
- OpenApi
- OpenAPI types re-exported from utoipa for convenience. Root object of the OpenAPI document.
- Param
Value - A parameter value with its serialization style
- Paths
- OpenAPI types re-exported from utoipa for convenience. Implements OpenAPI Paths Object.
- RawResult
- Represents the raw response data from an HTTP request.
- Redact
Options redaction - Options for configuring redaction behavior.
- Redacted
Result redaction - Result of a redacted JSON response containing both the real and redacted values.
- Redaction
Builder redaction - Builder for applying redactions to JSON responses.
- Secure
String - Secure wrapper for sensitive string data that automatically zeroes memory on drop.
- Security
Requirement - Security requirement specifying which scheme and scopes are needed.
- Server
- OpenAPI types re-exported from utoipa for convenience. Represents target server object. It can be used to alter server connection for path operations.
- Server
Builder - OpenAPI types re-exported from utoipa for convenience.
Builder for
Serverwith chainable configuration methods to create a newServer. - Status
Code - HTTP status codes re-exported from the
httpcrate. An HTTP status code (status-codein RFC 9110 et al.). - Value
Redaction Builder redaction - Builder for redacting arbitrary JSON values.
Enums§
- ApiClient
Error - Errors that can occur when using the ApiClient.
- ApiKey
Location - Location where an API key is passed.
- Authentication
- Authentication configuration for API requests.
- Authentication
Error - Errors that can occur during authentication processing.
- OAuth2
Error oauth2 - Errors that can occur during OAuth2 authentication.
- Param
Style - Parameter styles supported by OpenAPI 3.1 specification.
- RawBody
- Represents the body content of a raw HTTP response.
- Security
Scheme - OpenAPI security scheme configuration.
Traits§
- Parameter
Value - A trait alias for types that can be used as parameter values.
- Redactor
redaction - Trait for types that can be used to redact values.
- ToSchema
- The
ToSchemaderive macro for generating OpenAPI schemas. Types used in JSON request/response bodies should derive this trait. Trait for implementing OpenAPI Schema object. - ToYaml
yaml - Extension trait for serializing types to YAML.
Functions§
- redact_
value redaction - Create a redaction builder for an arbitrary JSON value.
Type Aliases§
- Yaml
Error yaml - Error type for YAML serialization operations.