@@ -92,7 +92,46 @@ impl HttpClient {
92
92
}
93
93
}
94
94
95
+ /// Send a request to the GitHub API and return the response.
95
96
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 > >
96
135
where
97
136
R : serde:: de:: DeserializeOwned ,
98
137
V : serde:: Serialize ,
@@ -109,16 +148,9 @@ impl HttpClient {
109
148
. context ( "failed to send graphql request" ) ?
110
149
. custom_error_for_status ( ) ?;
111
150
112
- let res : GraphResult < R > = resp. json_annotated ( ) . with_context ( || {
151
+ resp. json_annotated ( ) . with_context ( || {
113
152
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
+ } )
122
154
}
123
155
124
156
fn rest_paginated < F , T > ( & self , method : & Method , url : & GitHubUrl , mut f : F ) -> anyhow:: Result < ( ) >
@@ -160,6 +192,17 @@ impl HttpClient {
160
192
}
161
193
}
162
194
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
+
163
206
fn allow_not_found ( resp : Response , method : Method , url : & str ) -> Result < ( ) , anyhow:: Error > {
164
207
match resp. status ( ) {
165
208
StatusCode :: NOT_FOUND => {
@@ -181,9 +224,19 @@ struct GraphResult<T> {
181
224
182
225
#[ derive( Debug , serde:: Deserialize ) ]
183
226
struct GraphError {
227
+ #[ serde( rename = "type" ) ]
228
+ type_ : Option < GraphErrorType > ,
184
229
message : String ,
185
230
}
186
231
232
+ #[ derive( Debug , serde:: Deserialize , PartialEq , Eq ) ]
233
+ #[ serde( rename_all = "UPPERCASE" ) ]
234
+ enum GraphErrorType {
235
+ NotFound ,
236
+ #[ serde( other) ]
237
+ Other ,
238
+ }
239
+
187
240
#[ derive( serde:: Deserialize ) ]
188
241
struct GraphNodes < T > {
189
242
nodes : Vec < Option < T > > ,
0 commit comments