@@ -5,13 +5,41 @@ use crate::schema::{
5
5
} ;
6
6
use crate :: util:: errors:: AppResult ;
7
7
use crate :: views:: { EncodableCategory , EncodableCrate , EncodableKeyword } ;
8
- use axum_extra:: json;
9
- use axum_extra:: response:: ErasedJson ;
8
+ use axum:: Json ;
10
9
use diesel:: prelude:: * ;
11
10
use diesel_async:: { AsyncPgConnection , RunQueryDsl } ;
12
11
use futures_util:: FutureExt ;
13
12
use std:: future:: Future ;
14
13
14
+ #[ derive( Debug , Serialize , utoipa:: ToSchema ) ]
15
+ pub struct SummaryResponse {
16
+ /// The total number of downloads across all crates.
17
+ #[ schema( example = 123_456_789 ) ]
18
+ num_downloads : i64 ,
19
+
20
+ /// The total number of crates on crates.io.
21
+ #[ schema( example = 123_456 ) ]
22
+ num_crates : i64 ,
23
+
24
+ /// The 10 most recently created crates.
25
+ new_crates : Vec < EncodableCrate > ,
26
+
27
+ /// The 10 crates with the highest total number of downloads.
28
+ most_downloaded : Vec < EncodableCrate > ,
29
+
30
+ /// The 10 crates with the highest number of downloads within the last 90 days.
31
+ most_recently_downloaded : Vec < EncodableCrate > ,
32
+
33
+ /// The 10 most recently updated crates.
34
+ just_updated : Vec < EncodableCrate > ,
35
+
36
+ /// The 10 most popular keywords.
37
+ popular_keywords : Vec < EncodableKeyword > ,
38
+
39
+ /// The 10 most popular categories.
40
+ popular_categories : Vec < EncodableCategory > ,
41
+ }
42
+
15
43
/// Get front page data.
16
44
///
17
45
/// This endpoint returns a summary of the most important data for the front
@@ -20,9 +48,9 @@ use std::future::Future;
20
48
get,
21
49
path = "/api/v1/summary" ,
22
50
tag = "other" ,
23
- responses( ( status = 200 , description = "Successful Response" ) ) ,
51
+ responses( ( status = 200 , description = "Successful Response" , body = inline ( SummaryResponse ) ) ) ,
24
52
) ]
25
- pub async fn get_summary ( state : AppState ) -> AppResult < ErasedJson > {
53
+ pub async fn get_summary ( state : AppState ) -> AppResult < Json < SummaryResponse > > {
26
54
let mut conn = state. db_read ( ) . await ?;
27
55
28
56
let config = & state. config ;
@@ -37,10 +65,10 @@ pub async fn get_summary(state: AppState) -> AppResult<ErasedJson> {
37
65
popular_categories,
38
66
popular_keywords,
39
67
) = tokio:: try_join!(
40
- crates:: table. count( ) . get_result:: < i64 > ( & mut conn) . boxed( ) ,
68
+ crates:: table. count( ) . get_result( & mut conn) . boxed( ) ,
41
69
metadata:: table
42
70
. select( metadata:: total_downloads)
43
- . get_result:: < i64 > ( & mut conn)
71
+ . get_result( & mut conn)
44
72
. boxed( ) ,
45
73
crates:: table
46
74
. inner_join( crate_downloads:: table)
@@ -100,25 +128,18 @@ pub async fn get_summary(state: AppState) -> AppResult<ErasedJson> {
100
128
encode_crates( & mut conn, just_updated) ,
101
129
) ?;
102
130
103
- let popular_categories = popular_categories
104
- . into_iter ( )
105
- . map ( Category :: into)
106
- . collect :: < Vec < EncodableCategory > > ( ) ;
107
-
108
- let popular_keywords = popular_keywords
109
- . into_iter ( )
110
- . map ( Keyword :: into)
111
- . collect :: < Vec < EncodableKeyword > > ( ) ;
112
-
113
- Ok ( json ! ( {
114
- "num_downloads" : num_downloads,
115
- "num_crates" : num_crates,
116
- "new_crates" : new_crates,
117
- "most_downloaded" : most_downloaded,
118
- "most_recently_downloaded" : most_recently_downloaded,
119
- "just_updated" : just_updated,
120
- "popular_keywords" : popular_keywords,
121
- "popular_categories" : popular_categories,
131
+ let popular_categories = popular_categories. into_iter ( ) . map ( Category :: into) . collect ( ) ;
132
+ let popular_keywords = popular_keywords. into_iter ( ) . map ( Keyword :: into) . collect ( ) ;
133
+
134
+ Ok ( Json ( SummaryResponse {
135
+ num_downloads,
136
+ num_crates,
137
+ new_crates,
138
+ most_downloaded,
139
+ most_recently_downloaded,
140
+ just_updated,
141
+ popular_keywords,
142
+ popular_categories,
122
143
} ) )
123
144
}
124
145
0 commit comments