openapi_snapshot/
fetch.rs1use reqwest::blocking::Client;
2use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
3use serde_json::Value;
4use std::time::Duration;
5
6use crate::config::Config;
7use crate::errors::AppError;
8
9pub fn fetch_openapi(config: &Config) -> Result<Vec<u8>, AppError> {
10 let client = Client::builder()
11 .timeout(Duration::from_millis(config.timeout_ms))
12 .build()
13 .map_err(|err| AppError::Network(format!("client error: {err}")))?;
14
15 let headers = build_headers(&config.headers)?;
16 let response = client
17 .get(&config.url)
18 .headers(headers)
19 .send()
20 .map_err(|err| AppError::Network(format!("request failed: {err}")))?;
21
22 let status = response.status();
23 if !status.is_success() {
24 return Err(AppError::Network(format!(
25 "unexpected status: {status}"
26 )));
27 }
28
29 response
30 .bytes()
31 .map(|bytes| bytes.to_vec())
32 .map_err(|err| AppError::Network(format!("failed to read response: {err}")))
33}
34
35pub fn parse_json(bytes: &[u8]) -> Result<Value, AppError> {
36 serde_json::from_slice(bytes).map_err(|err| AppError::Json(format!("invalid JSON: {err}")))
37}
38
39fn build_headers(raw_headers: &[String]) -> Result<HeaderMap, AppError> {
40 let mut headers = HeaderMap::new();
41 for raw in raw_headers {
42 let (name, value) = parse_header(raw)?;
43 headers.insert(name, value);
44 }
45 Ok(headers)
46}
47
48fn parse_header(raw: &str) -> Result<(HeaderName, HeaderValue), AppError> {
49 let mut split = raw.splitn(2, ':');
50 let name = split
51 .next()
52 .map(str::trim)
53 .filter(|value| !value.is_empty())
54 .ok_or_else(|| AppError::Usage(format!("invalid header format: {raw}")))?;
55 let value = split
56 .next()
57 .map(str::trim)
58 .ok_or_else(|| AppError::Usage(format!("invalid header format: {raw}")))?;
59 let header_name = HeaderName::from_bytes(name.as_bytes())
60 .map_err(|_| AppError::Usage(format!("invalid header name: {name}")))?;
61 let header_value = HeaderValue::from_str(value)
62 .map_err(|_| AppError::Usage(format!("invalid header value for: {name}")))?;
63 Ok((header_name, header_value))
64}