viewpoint_core/api/
mod.rs

1//! API testing support for making HTTP requests outside of browser context.
2//!
3//! This module provides `APIRequestContext` for making HTTP requests directly,
4//! without needing a browser. This is useful for:
5//! - Setting up test data via API
6//! - Verifying backend state after UI actions
7//! - Getting authentication tokens
8//! - Running API-only tests without browser overhead
9//!
10//! # Example
11//!
12//! ```no_run
13//! use viewpoint_core::api::{APIRequestContext, APIContextOptions};
14//!
15//! # async fn example() -> Result<(), viewpoint_core::api::APIError> {
16//! // Create a standalone API context
17//! let api = APIRequestContext::new(
18//!     APIContextOptions::new()
19//!         .base_url("https://api.example.com")
20//! ).await?;
21//!
22//! // Make a GET request
23//! let response = api.get("/users").send().await?;
24//! assert!(response.ok());
25//!
26//! // Make a POST request with JSON body
27//! let user = serde_json::json!({ "name": "John", "email": "john@example.com" });
28//! let response = api.post("/users")
29//!     .json(&user)
30//!     .send()
31//!     .await?;
32//!
33//! // Parse JSON response
34//! let created_user: serde_json::Value = response.json().await?;
35//! # Ok(())
36//! # }
37//! ```
38
39mod context;
40pub mod cookies;
41mod options;
42mod request;
43mod response;
44
45pub use context::APIRequestContext;
46pub use options::{APIContextOptions, CredentialSend, HttpCredentials, ProxyConfig};
47pub use request::{APIRequestBuilder, MultipartField};
48pub use response::APIResponse;
49
50use std::time::Duration;
51use thiserror::Error;
52
53/// Errors that can occur during API operations.
54#[derive(Error, Debug)]
55pub enum APIError {
56    /// HTTP request failed.
57    #[error("request failed: {0}")]
58    RequestFailed(String),
59
60    /// Request timed out.
61    #[error("request timeout after {0:?}")]
62    Timeout(Duration),
63
64    /// Failed to build request.
65    #[error("failed to build request: {0}")]
66    BuildError(String),
67
68    /// Failed to parse response body.
69    #[error("failed to parse response: {0}")]
70    ParseError(String),
71
72    /// Invalid URL.
73    #[error("invalid URL: {0}")]
74    InvalidUrl(String),
75
76    /// JSON serialization/deserialization error.
77    #[error("JSON error: {0}")]
78    JsonError(String),
79
80    /// Context is disposed.
81    #[error("API context is disposed")]
82    Disposed,
83
84    /// HTTP client error.
85    #[error("HTTP error: {0}")]
86    Http(#[from] reqwest::Error),
87}
88
89/// HTTP method for API requests.
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub enum HttpMethod {
92    /// GET method.
93    Get,
94    /// POST method.
95    Post,
96    /// PUT method.
97    Put,
98    /// PATCH method.
99    Patch,
100    /// DELETE method.
101    Delete,
102    /// HEAD method.
103    Head,
104}
105
106impl HttpMethod {
107    /// Convert to reqwest Method.
108    pub fn to_reqwest(&self) -> reqwest::Method {
109        match self {
110            Self::Get => reqwest::Method::GET,
111            Self::Post => reqwest::Method::POST,
112            Self::Put => reqwest::Method::PUT,
113            Self::Patch => reqwest::Method::PATCH,
114            Self::Delete => reqwest::Method::DELETE,
115            Self::Head => reqwest::Method::HEAD,
116        }
117    }
118}
119
120#[cfg(test)]
121mod tests;