ephemeris_forge_github/api/
http.rs1mod access;
4mod actions;
5mod autolinks;
6mod custom_properties;
7mod environments;
8mod labels;
9mod pages;
10mod release;
11mod repository;
12mod rulesets;
13mod security;
14mod variables;
15mod webhooks;
16
17use std::time::Duration;
18
19use ephemeris_forge::{Http, RetryPolicy, TransportBuildError};
20use ephemeris_token::Token;
21use facet::Facet;
22use reqwest::header::{ACCEPT, HeaderName, HeaderValue};
23use reqwest::{Method, Url};
24
25use super::error::ForgeError;
26
27const PAGE_SIZE: usize = 100;
28
29#[derive(Clone, Debug)]
34pub struct HttpApi {
35 pub(crate) http: Http,
36}
37
38impl HttpApi {
39 pub fn new(base: &Url, token: Token) -> Result<Self, TransportBuildError> {
45 let http = Http::new(base.clone(), token, Duration::from_secs(30))?
46 .with_header(
47 ACCEPT,
48 HeaderValue::from_static("application/vnd.github+json"),
49 )
50 .with_header(
51 HeaderName::from_static("x-github-api-version"),
52 HeaderValue::from_static("2026-03-10"),
53 );
54 Ok(Self { http })
55 }
56
57 #[must_use]
59 pub fn with_retry(mut self, retry: RetryPolicy) -> Self {
60 self.http = self.http.with_retry(retry);
61 self
62 }
63
64 async fn send<T: for<'a> Facet<'a>>(
65 &self,
66 method: Method,
67 path: &str,
68 body: Option<String>,
69 ) -> Result<T, ForgeError> {
70 let raw = body.as_deref();
71 Ok(self.http.json(method, path, raw).await?)
72 }
73
74 async fn optional<T: for<'a> Facet<'a>>(&self, path: &str) -> Result<Option<T>, ForgeError> {
76 Ok(self.http.json_optional(Method::GET, path, None).await?)
77 }
78
79 async fn empty(
80 &self,
81 method: Method,
82 path: &str,
83 body: Option<String>,
84 ) -> Result<(), ForgeError> {
85 let raw = body.as_deref();
86 self.http.send(method, path, raw).await?;
87 Ok(())
88 }
89
90 async fn paged<T: for<'a> Facet<'a>>(&self, path: &str) -> Result<Vec<T>, ForgeError> {
91 self.paged_in(path, PAGE_SIZE, |values: Vec<T>| values)
92 .await
93 }
94
95 async fn paged_in<R: for<'a> Facet<'a>, T>(
96 &self,
97 path: &str,
98 page_size: usize,
99 items: fn(R) -> Vec<T>,
100 ) -> Result<Vec<T>, ForgeError> {
101 Ok(self
102 .http
103 .paged_in(
104 page_size,
105 path,
106 |page| format!("per_page={page_size}&page={page}"),
107 items,
108 )
109 .await?)
110 }
111}