Skip to main content

late/apis/
validate_api.rs

1/*
2 * Zernio API
3 *
4 * API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api
5 *
6 * The version of the OpenAPI document: 1.0.4
7 * Contact: support@zernio.com
8 * Generated by: https://openapi-generator.tech
9 */
10
11use super::{configuration, ContentType, Error};
12use crate::{apis::ResponseContent, models};
13use reqwest;
14use serde::{de::Error as _, Deserialize, Serialize};
15
16/// struct for typed errors of method [`validate_media`]
17#[derive(Debug, Clone, Serialize, Deserialize)]
18#[serde(untagged)]
19pub enum ValidateMediaError {
20    Status401(models::InlineObject),
21    UnknownValue(serde_json::Value),
22}
23
24/// struct for typed errors of method [`validate_post`]
25#[derive(Debug, Clone, Serialize, Deserialize)]
26#[serde(untagged)]
27pub enum ValidatePostError {
28    Status401(models::InlineObject),
29    UnknownValue(serde_json::Value),
30}
31
32/// struct for typed errors of method [`validate_post_length`]
33#[derive(Debug, Clone, Serialize, Deserialize)]
34#[serde(untagged)]
35pub enum ValidatePostLengthError {
36    Status401(models::InlineObject),
37    UnknownValue(serde_json::Value),
38}
39
40/// struct for typed errors of method [`validate_subreddit`]
41#[derive(Debug, Clone, Serialize, Deserialize)]
42#[serde(untagged)]
43pub enum ValidateSubredditError {
44    Status401(models::InlineObject),
45    UnknownValue(serde_json::Value),
46}
47
48/// Check if a media URL is accessible and return metadata (content type, file size) plus per-platform size limit comparisons.  Performs a HEAD request (with GET fallback) to detect content type and size. Rejects private/localhost URLs for SSRF protection.  Platform limits are sourced from each platform's actual upload constraints.
49pub async fn validate_media(
50    configuration: &configuration::Configuration,
51    validate_media_request: models::ValidateMediaRequest,
52) -> Result<models::ValidateMedia200Response, Error<ValidateMediaError>> {
53    // add a prefix to parameters to efficiently prevent name collisions
54    let p_body_validate_media_request = validate_media_request;
55
56    let uri_str = format!("{}/v1/tools/validate/media", configuration.base_path);
57    let mut req_builder = configuration
58        .client
59        .request(reqwest::Method::POST, &uri_str);
60
61    if let Some(ref user_agent) = configuration.user_agent {
62        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
63    }
64    if let Some(ref token) = configuration.bearer_access_token {
65        req_builder = req_builder.bearer_auth(token.to_owned());
66    };
67    req_builder = req_builder.json(&p_body_validate_media_request);
68
69    let req = req_builder.build()?;
70    let resp = configuration.client.execute(req).await?;
71
72    let status = resp.status();
73    let content_type = resp
74        .headers()
75        .get("content-type")
76        .and_then(|v| v.to_str().ok())
77        .unwrap_or("application/octet-stream");
78    let content_type = super::ContentType::from(content_type);
79
80    if !status.is_client_error() && !status.is_server_error() {
81        let content = resp.text().await?;
82        match content_type {
83            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
84            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ValidateMedia200Response`"))),
85            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ValidateMedia200Response`")))),
86        }
87    } else {
88        let content = resp.text().await?;
89        let entity: Option<ValidateMediaError> = serde_json::from_str(&content).ok();
90        Err(Error::ResponseError(ResponseContent {
91            status,
92            content,
93            entity,
94        }))
95    }
96}
97
98/// Dry-run the full post validation pipeline without publishing. Catches issues like missing media for Instagram/TikTok/YouTube, hashtag limits, invalid thread formats, Facebook Reel requirements, and character limit violations.  Accepts the same body as POST /v1/posts. Does NOT validate accounts, process media, or track usage. Account lookups are limit-only: a twitter accountId is resolved, scoped to the caller, only to pick the 280 vs 25000 character limit. Missing, foreign, or invalid ids fall back to 280 and never error.  Returns errors for failures and warnings for near-limit content (>90% of character limit).
99pub async fn validate_post(
100    configuration: &configuration::Configuration,
101    validate_post_request: models::ValidatePostRequest,
102) -> Result<models::ValidatePost200Response, Error<ValidatePostError>> {
103    // add a prefix to parameters to efficiently prevent name collisions
104    let p_body_validate_post_request = validate_post_request;
105
106    let uri_str = format!("{}/v1/tools/validate/post", configuration.base_path);
107    let mut req_builder = configuration
108        .client
109        .request(reqwest::Method::POST, &uri_str);
110
111    if let Some(ref user_agent) = configuration.user_agent {
112        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
113    }
114    if let Some(ref token) = configuration.bearer_access_token {
115        req_builder = req_builder.bearer_auth(token.to_owned());
116    };
117    req_builder = req_builder.json(&p_body_validate_post_request);
118
119    let req = req_builder.build()?;
120    let resp = configuration.client.execute(req).await?;
121
122    let status = resp.status();
123    let content_type = resp
124        .headers()
125        .get("content-type")
126        .and_then(|v| v.to_str().ok())
127        .unwrap_or("application/octet-stream");
128    let content_type = super::ContentType::from(content_type);
129
130    if !status.is_client_error() && !status.is_server_error() {
131        let content = resp.text().await?;
132        match content_type {
133            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
134            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ValidatePost200Response`"))),
135            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ValidatePost200Response`")))),
136        }
137    } else {
138        let content = resp.text().await?;
139        let entity: Option<ValidatePostError> = serde_json::from_str(&content).ok();
140        Err(Error::ResponseError(ResponseContent {
141            status,
142            content,
143            entity,
144        }))
145    }
146}
147
148/// Check weighted character count per platform and whether the text is within each platform's limit.  Twitter/X uses weighted counting (URLs = 23 chars via t.co, emojis = 2 chars). All other platforms use plain character length.  Returns counts and limits for all 15 supported platform variants.
149pub async fn validate_post_length(
150    configuration: &configuration::Configuration,
151    validate_post_length_request: models::ValidatePostLengthRequest,
152) -> Result<models::ValidatePostLength200Response, Error<ValidatePostLengthError>> {
153    // add a prefix to parameters to efficiently prevent name collisions
154    let p_body_validate_post_length_request = validate_post_length_request;
155
156    let uri_str = format!("{}/v1/tools/validate/post-length", configuration.base_path);
157    let mut req_builder = configuration
158        .client
159        .request(reqwest::Method::POST, &uri_str);
160
161    if let Some(ref user_agent) = configuration.user_agent {
162        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
163    }
164    if let Some(ref token) = configuration.bearer_access_token {
165        req_builder = req_builder.bearer_auth(token.to_owned());
166    };
167    req_builder = req_builder.json(&p_body_validate_post_length_request);
168
169    let req = req_builder.build()?;
170    let resp = configuration.client.execute(req).await?;
171
172    let status = resp.status();
173    let content_type = resp
174        .headers()
175        .get("content-type")
176        .and_then(|v| v.to_str().ok())
177        .unwrap_or("application/octet-stream");
178    let content_type = super::ContentType::from(content_type);
179
180    if !status.is_client_error() && !status.is_server_error() {
181        let content = resp.text().await?;
182        match content_type {
183            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
184            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ValidatePostLength200Response`"))),
185            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ValidatePostLength200Response`")))),
186        }
187    } else {
188        let content = resp.text().await?;
189        let entity: Option<ValidatePostLengthError> = serde_json::from_str(&content).ok();
190        Err(Error::ResponseError(ResponseContent {
191            status,
192            content,
193            entity,
194        }))
195    }
196}
197
198/// Check if a subreddit exists and return basic info (title, subscriber count, NSFW status, post types allowed).  When accountId is provided, uses authenticated Reddit OAuth API with automatic token refresh (recommended). Falls back to Reddit's public JSON API, which may be unreliable from server IPs. Returns exists: false for private, banned, or nonexistent subreddits.
199pub async fn validate_subreddit(
200    configuration: &configuration::Configuration,
201    name: &str,
202    account_id: Option<&str>,
203) -> Result<models::ValidateSubreddit200Response, Error<ValidateSubredditError>> {
204    // add a prefix to parameters to efficiently prevent name collisions
205    let p_query_name = name;
206    let p_query_account_id = account_id;
207
208    let uri_str = format!("{}/v1/tools/validate/subreddit", configuration.base_path);
209    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
210
211    req_builder = req_builder.query(&[("name", &p_query_name.to_string())]);
212    if let Some(ref param_value) = p_query_account_id {
213        req_builder = req_builder.query(&[("accountId", &param_value.to_string())]);
214    }
215    if let Some(ref user_agent) = configuration.user_agent {
216        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
217    }
218    if let Some(ref token) = configuration.bearer_access_token {
219        req_builder = req_builder.bearer_auth(token.to_owned());
220    };
221
222    let req = req_builder.build()?;
223    let resp = configuration.client.execute(req).await?;
224
225    let status = resp.status();
226    let content_type = resp
227        .headers()
228        .get("content-type")
229        .and_then(|v| v.to_str().ok())
230        .unwrap_or("application/octet-stream");
231    let content_type = super::ContentType::from(content_type);
232
233    if !status.is_client_error() && !status.is_server_error() {
234        let content = resp.text().await?;
235        match content_type {
236            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
237            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ValidateSubreddit200Response`"))),
238            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ValidateSubreddit200Response`")))),
239        }
240    } else {
241        let content = resp.text().await?;
242        let entity: Option<ValidateSubredditError> = serde_json::from_str(&content).ok();
243        Err(Error::ResponseError(ResponseContent {
244            status,
245            content,
246            entity,
247        }))
248    }
249}