@@ -33,6 +33,21 @@ use url::form_urlencoded;
33
33
34
34
use super :: cache:: CachePolicy ;
35
35
36
+ // Introduce SearchError as new error type
37
+ #[ derive( Debug , thiserror:: Error ) ]
38
+ pub enum SearchError {
39
+ #[ error( "crates.io error: {0}" ) ]
40
+ CratesIo ( String ) ,
41
+ #[ error( transparent) ]
42
+ Other ( #[ from] anyhow:: Error ) ,
43
+ }
44
+
45
+ impl From < sqlx:: Error > for SearchError {
46
+ fn from ( err : sqlx:: Error ) -> Self {
47
+ SearchError :: Other ( anyhow:: Error :: from ( err) )
48
+ }
49
+ }
50
+
36
51
/// Number of release in home page
37
52
const RELEASES_IN_HOME : i64 = 15 ;
38
53
/// Releases in /releases page
@@ -149,8 +164,13 @@ async fn get_search_results(
149
164
conn : & mut sqlx:: PgConnection ,
150
165
registry : & RegistryApi ,
151
166
query_params : & str ,
152
- ) -> Result < SearchResult , anyhow:: Error > {
153
- let crate :: registry_api:: Search { crates, meta } = registry. search ( query_params) . await ?;
167
+ ) -> Result < SearchResult , SearchError > {
168
+ // Capture responses returned by registry
169
+ let result = registry. search ( query_params) . await ;
170
+ let crate :: registry_api:: Search { crates, meta } = match result {
171
+ Ok ( results_from_search_request) => results_from_search_request,
172
+ Err ( err) => return handle_registry_error ( err) ,
173
+ } ;
154
174
155
175
let names = Arc :: new (
156
176
crates
@@ -233,6 +253,37 @@ async fn get_search_results(
233
253
} )
234
254
}
235
255
256
+ // Categorize errors from registry
257
+ fn handle_registry_error ( err : anyhow:: Error ) -> Result < SearchResult , SearchError > {
258
+ // Capture crates.io API error
259
+ if let Some ( registry_request_error) = err. downcast_ref :: < reqwest:: Error > ( ) {
260
+ if let Some ( status) = registry_request_error. status ( ) {
261
+ if status. is_client_error ( ) || status. is_server_error ( ) {
262
+ return Err ( SearchError :: CratesIo ( format ! (
263
+ "crates.io returned {}: {}" ,
264
+ status, registry_request_error
265
+ ) ) ) ;
266
+ }
267
+ }
268
+ }
269
+ // Move all other error types to this wrapper
270
+ Err ( SearchError :: Other ( err) )
271
+ }
272
+
273
+ //Error message to gracefully display
274
+ fn create_search_error_response ( query : String , sort_by : String ) -> Search {
275
+ Search {
276
+ title : "Search service is not currently available" . to_owned ( ) ,
277
+ releases : vec ! [ ] ,
278
+ search_query : Some ( query) ,
279
+ search_sort_by : Some ( sort_by) ,
280
+ previous_page_link : None ,
281
+ next_page_link : None ,
282
+ release_type : ReleaseType :: Search ,
283
+ status : http:: StatusCode :: SERVICE_UNAVAILABLE ,
284
+ }
285
+ }
286
+
236
287
#[ derive( Template ) ]
237
288
#[ template( path = "core/home.html" ) ]
238
289
#[ derive( Debug , Clone , PartialEq , Eq ) ]
@@ -589,19 +640,32 @@ pub(crate) async fn search_handler(
589
640
}
590
641
}
591
642
592
- get_search_results ( & mut conn, & registry, query_params) . await ?
643
+ get_search_results ( & mut conn, & registry, query_params) . await
593
644
} else if !query. is_empty ( ) {
594
645
let query_params: String = form_urlencoded:: Serializer :: new ( String :: new ( ) )
595
646
. append_pair ( "q" , & query)
596
647
. append_pair ( "sort" , & sort_by)
597
648
. append_pair ( "per_page" , & RELEASES_IN_RELEASES . to_string ( ) )
598
649
. finish ( ) ;
599
650
600
- get_search_results ( & mut conn, & registry, & query_params) . await ?
651
+ get_search_results ( & mut conn, & registry, & query_params) . await
601
652
} else {
602
653
return Err ( AxumNope :: NoResults ) ;
603
654
} ;
604
655
656
+ let search_result = match search_result {
657
+ Ok ( result) => result,
658
+ Err ( SearchError :: CratesIo ( _) ) => {
659
+ // Return a user-friendly error response
660
+ return Ok ( create_search_error_response ( query, sort_by) . into_response ( ) ) ;
661
+ }
662
+ Err ( SearchError :: Other ( err) ) => {
663
+ // For other errors, propagate them normally
664
+ // NOTE - Errrors that are not 400x or 500x will be logged to Sentry
665
+ return Err ( err. into ( ) ) ;
666
+ }
667
+ } ;
668
+
605
669
let title = if search_result. results . is_empty ( ) {
606
670
format ! ( "No results found for '{query}'" )
607
671
} else {
0 commit comments