Skip to content
This repository was archived by the owner on Mar 31, 2025. It is now read-only.

Commit 08cfdf3

Browse files
committed
create graphql_opt method
1 parent c268d5b commit 08cfdf3

File tree

2 files changed

+65
-12
lines changed

2 files changed

+65
-12
lines changed

src/github/api/mod.rs

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,46 @@ impl HttpClient {
9292
}
9393
}
9494

95+
/// Send a request to the GitHub API and return the response.
9596
fn graphql<R, V>(&self, query: &str, variables: V, org: &str) -> anyhow::Result<R>
97+
where
98+
R: serde::de::DeserializeOwned,
99+
V: serde::Serialize,
100+
{
101+
let res = self.send_graphql_req(query, variables, org)?;
102+
103+
if let Some(error) = res.errors.first() {
104+
bail!("graphql error: {}", error.message);
105+
}
106+
107+
read_graphql_data(res)
108+
}
109+
110+
/// Send a request to the GitHub API and return the response.
111+
/// If the request contains the error type `NOT_FOUND`, this method returns `Ok(None)`.
112+
fn graphql_opt<R, V>(&self, query: &str, variables: V, org: &str) -> anyhow::Result<Option<R>>
113+
where
114+
R: serde::de::DeserializeOwned,
115+
V: serde::Serialize,
116+
{
117+
let res = self.send_graphql_req(query, variables, org)?;
118+
119+
if let Some(error) = res.errors.first() {
120+
if error.type_ == Some(GraphErrorType::NotFound) {
121+
return Ok(None);
122+
}
123+
bail!("graphql error: {}", error.message);
124+
}
125+
126+
read_graphql_data(res)
127+
}
128+
129+
fn send_graphql_req<R, V>(
130+
&self,
131+
query: &str,
132+
variables: V,
133+
org: &str,
134+
) -> anyhow::Result<GraphResult<R>>
96135
where
97136
R: serde::de::DeserializeOwned,
98137
V: serde::Serialize,
@@ -109,16 +148,9 @@ impl HttpClient {
109148
.context("failed to send graphql request")?
110149
.custom_error_for_status()?;
111150

112-
let res: GraphResult<R> = resp.json_annotated().with_context(|| {
151+
resp.json_annotated().with_context(|| {
113152
format!("Failed to decode response body on graphql request with query '{query}'")
114-
})?;
115-
if let Some(error) = res.errors.first() {
116-
bail!("graphql error: {}", error.message);
117-
} else if let Some(data) = res.data {
118-
Ok(data)
119-
} else {
120-
bail!("missing graphql data");
121-
}
153+
})
122154
}
123155

124156
fn rest_paginated<F, T>(&self, method: &Method, url: &GitHubUrl, mut f: F) -> anyhow::Result<()>
@@ -160,6 +192,17 @@ impl HttpClient {
160192
}
161193
}
162194

195+
fn read_graphql_data<R>(res: GraphResult<R>) -> anyhow::Result<R>
196+
where
197+
R: serde::de::DeserializeOwned,
198+
{
199+
if let Some(data) = res.data {
200+
Ok(data)
201+
} else {
202+
bail!("missing graphql data");
203+
}
204+
}
205+
163206
fn allow_not_found(resp: Response, method: Method, url: &str) -> Result<(), anyhow::Error> {
164207
match resp.status() {
165208
StatusCode::NOT_FOUND => {
@@ -181,9 +224,19 @@ struct GraphResult<T> {
181224

182225
#[derive(Debug, serde::Deserialize)]
183226
struct GraphError {
227+
#[serde(rename = "type")]
228+
type_: Option<GraphErrorType>,
184229
message: String,
185230
}
186231

232+
#[derive(Debug, serde::Deserialize, PartialEq, Eq)]
233+
#[serde(rename_all = "UPPERCASE")]
234+
enum GraphErrorType {
235+
NotFound,
236+
#[serde(other)]
237+
Other,
238+
}
239+
187240
#[derive(serde::Deserialize)]
188241
struct GraphNodes<T> {
189242
nodes: Vec<Option<T>>,

src/github/api/read.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,9 @@ impl GithubRead for GitHubApiRead {
272272
is_archived: bool,
273273
}
274274

275-
let result: Wrapper = self
275+
let result: Option<Wrapper> = self
276276
.client
277-
.graphql(
277+
.graphql_opt(
278278
QUERY,
279279
Params {
280280
owner: org,
@@ -284,7 +284,7 @@ impl GithubRead for GitHubApiRead {
284284
)
285285
.with_context(|| format!("failed to retrieve repo `{org}/{repo}`"))?;
286286

287-
let repo = result.repository.map(|repo_response| Repo {
287+
let repo = result.and_then(|r| r.repository).map(|repo_response| Repo {
288288
node_id: repo_response.id,
289289
name: repo.to_string(),
290290
description: repo_response.description.unwrap_or_default(),

0 commit comments

Comments
 (0)