@@ -9,30 +9,53 @@ use axum::body::Body;
9
9
use axum:: handler:: Handler ;
10
10
use axum:: http:: { Method , Request , StatusCode } ;
11
11
use axum:: response:: IntoResponse ;
12
+ use lazy_static:: lazy_static;
12
13
use log:: trace;
13
14
use tower:: Service ;
14
15
16
+ lazy_static ! {
17
+ static ref API_VERSION : semver:: Version = env!( "CARGO_PKG_VERSION" ) . parse( ) . expect( & format!(
18
+ "failed to parse CARGO_PKG_VERSION `{}`" ,
19
+ env!( "CARGO_PKG_VERSION" )
20
+ ) ) ;
21
+ }
22
+
15
23
/// Parses the URI of `req` and routes it to respective component.
16
24
pub async fn handle ( mut req : Request < Body > ) -> impl IntoResponse {
25
+ #[ inline]
26
+ fn not_found ( path : & str ) -> ( StatusCode , String ) {
27
+ ( StatusCode :: NOT_FOUND , format ! ( "Route `/{path}` not found" ) )
28
+ }
29
+
17
30
trace ! ( target: "app::handle" , "begin HTTP request handling {:?}" , req) ;
18
31
let path = req. uri ( ) . path ( ) . trim_start_matches ( '/' ) ;
19
- let path = path
32
+ let ( ver , path) = path
20
33
. strip_prefix ( "api" )
21
- . ok_or ( ( StatusCode :: NOT_FOUND , format ! ( "Route `/{ path}` not found" ) ) ) ?
34
+ . ok_or_else ( || not_found ( path) ) ?
22
35
. trim_start_matches ( '/' )
23
- // TODO: Parse SemVer, support v0, v0.1 etc.
24
- . strip_prefix ( "v0.1.0" )
25
- . ok_or ( (
36
+ . strip_prefix ( 'v' )
37
+ . ok_or_else ( || not_found ( path) ) ?
38
+ . split_once ( '/' )
39
+ . ok_or_else ( || not_found ( path) ) ?;
40
+ let ver = ver. parse :: < semver:: Version > ( ) . map_err ( |e| {
41
+ (
42
+ StatusCode :: BAD_REQUEST ,
43
+ format ! ( "Failed to parse SemVer version from {path}: {e}" ) ,
44
+ )
45
+ } ) ?;
46
+ if ver > * API_VERSION {
47
+ return Err ( (
26
48
StatusCode :: NOT_IMPLEMENTED ,
27
- "Unsupported API version" . into ( ) ,
28
- ) ) ?
29
- . trim_start_matches ( '/' ) ;
49
+ format ! ( "Unsupported API version `{ver}`" ) ,
50
+ ) ) ;
51
+ }
30
52
let ( head, tail) = path
53
+ . trim_start_matches ( '/' )
31
54
. split_once ( "/_" )
32
55
. map ( |( left, right) | ( left. to_string ( ) , format ! ( "_{right}" ) ) )
33
56
. unwrap_or ( ( path. to_string ( ) , "" . into ( ) ) ) ;
34
57
if head. is_empty ( ) {
35
- return Err ( ( StatusCode :: NOT_FOUND , format ! ( "Route `/{ path}` not found" ) ) ) ;
58
+ return Err ( not_found ( path) ) ;
36
59
}
37
60
38
61
let extensions = req. extensions_mut ( ) ;
0 commit comments