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;