Commencez avec des exemples et des procédures pas à pas sur notre site Web!
Vous n'avez pas le temps de lire les documents? Vérifier
✅ fonctionne en stable ✅ fonctionne rapidement ✅ n'utilise pas dangereux
Documentation
Thruster est un cadre Web qui vise aux développeurs d'être productifs et cohérents entre les projets et les équipes. Ses objectifs sont d'être:
Propulseur aussi
unsafeLe thruster peut être exécuté avec différents backends de serveur et représente une couche bien emballée sur eux. Cela signifie qu'il peut suivre les derniers et meilleurs changements par rapport à Hyper, Actix ou même Thruterserver, un moteur HTTP à domicile.
Basé sur des cadres comme KOA et Express, Thruster vise à être un plaisir de se développer.
Pour exécuter l'exemple cargo run --example <example-name> . Par exemple, cargo run --example hello_world et ouvrez http: // localhost: 4321 /
Les pièces principales qui font du nouveau travail d'attente asynchrones consiste à désigner les fonctions middleware avec l'attribut #[middleware_fn] (qui marque le middleware de sorte qu'il est compatible avec la version à terme stable sur laquelle le propulseur est construit,) puis le m! macro dans les routes réelles.
Un exemple simple pour l'utilisation de l'attente asynchrone est:
use std :: boxed :: Box ;
use std :: future :: Future ;
use std :: pin :: Pin ;
use std :: time :: Instant ;
use thruster :: { App , BasicContext as Ctx , Request } ;
use thruster :: { m , middleware_fn , MiddlewareNext , MiddlewareResult , Server , ThrusterServer } ;
# [ middleware_fn ]
async fn profile ( context : Ctx , next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
let start_time = Instant :: now ( ) ;
context = next ( context ) . await ;
let elapsed_time = start_time . elapsed ( ) ;
println ! (
"[{}μs] {} -- {}" ,
elapsed_time . as_micros ( ) ,
context . request . method ( ) ,
context . request . path ( )
) ;
Ok ( context )
}
# [ middleware_fn ]
async fn plaintext ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
let val = "Hello, World!" ;
context . body ( val ) ;
Ok ( context )
}
# [ middleware_fn ]
async fn four_oh_four ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
context . status ( 404 ) ;
context . body ( "Whoops! That route doesn't exist!" ) ;
Ok ( context )
}
# [ tokio :: main ]
fn main ( ) {
println ! ( "Starting server..." ) ;
let mut app = App :: < Request , Ctx , ( ) > :: new_basic ( ) ;
app . get ( "/plaintext" , m ! [ profile , plaintext ] ) ;
app . set404 ( m ! [ four_oh_four ] ) ;
let server = Server :: new ( app ) ;
server . build ( "0.0.0.0" , 4321 ) . await ;
}Voici un bel exemple
use thruster :: errors :: ThrusterError as Error ;
use thruster :: proc :: { m , middleware_fn } ;
use thruster :: { map_try , App , BasicContext as Ctx , Request } ;
use thruster :: { MiddlewareNext , MiddlewareResult , MiddlewareReturnValue , Server , ThrusterServer } ;
# [ middleware_fn ]
async fn plaintext ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
let val = "Hello, World!" ;
context . body ( val ) ;
Ok ( context )
}
# [ middleware_fn ]
async fn error ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
let res = "Hello, world" . parse :: < u32 > ( )
. map_err ( |_| {
let mut context = Ctx :: default ( ) ;
context . status ( 400 ) ;
ThrusterError {
context ,
message : "Custom error message" . to_string ( ) ,
cause : None ,
}
} ? ;
context . body ( & format ! ( "{}" , non_existent_param ) ) ;
Ok ( context )
}
# [ tokio :: main ]
fn main ( ) {
println ! ( "Starting server..." ) ;
let app = App :: < Request , Ctx , ( ) > :: new_basic ( )
. get ( "/plaintext" , m ! [ plaintext ] )
. get ( "/error" , m ! [ error ] ) ;
let server = Server :: new ( app ) ;
server . build ( "0.0.0.0" , 4321 ) . await ;
} Le thruster fournit une suite de tests facile pour tester vos points de terminaison, incluez simplement le module testing comme ci-dessous:
let mut app = App :: < Request , Ctx , ( ) > :: new_basic ( ) ;
.. .
app . get ( "/plaintext" , m ! [ plaintext ] ) ;
.. .
let result = testing :: get ( app , "/plaintext" ) ;
assert ! ( result . body == "Hello, World!" ) ; Le middleware est super facile à faire! Créez simplement une fonction et exportez-la au niveau du module. Ci-dessous, vous verrez une pièce de middleware qui permet le profilage des demandes:
# [ middleware_fn ]
async fn profiling < C : ' static + Context + Send > (
mut context : C ,
next : MiddlewareNext < C > ,
) -> MiddlewareResult < C > {
let start_time = Instant :: now ( ) ;
context = next ( context ) . await ? ;
let elapsed_time = start_time . elapsed ( ) ;
info ! ( "[{}μs] {}" , elapsed_time . as_micros ( ) , context . route ( ) ) ;
Ok ( context )
}Vous pouvez constater que vous souhaitez permettre des données plus spécifiques stockées sur le contexte, par exemple, vous souhaitez peut-être pouvoir hydrater les paramètres de requête en un hashmap pour une utilisation ultérieure par d'autres moyens de Middlewares. Pour ce faire, vous pouvez créer un trait supplémentaire pour le contexte auquel les moyens de Middlewares en aval doivent adhérer. Consultez le middleware Query_Params fourni pour un exemple.
Le thruster est capable de simplement fournir la couche de routage au-dessus d'un serveur d'une certaine sorte, par exemple, dans l'hyper extrait ci-dessus. Cela peut être appliqué largement à n'importe quel backend, tant que le serveur implémente ThrusterServer .
use async_trait :: async_trait ;
# [ async_trait ]
pub trait ThrusterServer {
type Context : Context + Send ;
type Response : Send ;
type Request : RequestWithParams + Send ;
fn new ( App < Self :: Request , Self :: Context > ) -> Self ;
async fn build ( self , host : & str , port : u16 ) ;
}Il doit y avoir:
Dans la fonction build , l'implémentation du serveur doit:
let matched = app.resolve_from_method_and_path(<some method>, <some path>); (Cela fournit le routage réel.)app.resolve(<incoming request>, matched) (cela exécute le middleware enchaîné.) fn ip_guard ( head : & RequestHead ) -> bool {
// Check for the cloudflare IP header
let ip = if let Some ( val ) = head . headers ( ) . get ( CF_IP_HEADER ) {
val . to_str ( ) . unwrap_or ( "" ) . to_owned ( )
} else if let Some ( val ) = head . peer_addr {
val . to_string ( )
} else {
return false ;
} ;
"1.2.3.4" . contains ( & ip )
}
# [ actix_web :: post ( "/ping" ) ]
async fn ping ( ) -> Result < HttpResponse , UserPersonalError > {
Ok ( HttpResponse :: Ok ( ) . body ( "pong" ) )
}
.. .
web :: scope ( "/*" )
// This is confusing, but we catch all routes that _aren't_
// ip guarded and return an error.
. guard ( guard :: Not ( ip_guard ) )
. route ( "/*" , web :: to ( HttpResponse :: Forbidden ) ) ,
)
. service ( ping ) ;
.. .Voici le propulseur:
# [ middleware_fn ]
async fn ip_guard ( mut context : Ctx , next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
if "1.2.3.4" . contains ( & context . headers ( ) . get ( "Auth-Token" ) . unwrap_or ( "" ) ) {
context = next ( context ) . await ? ;
Ok ( context )
} else {
Err ( Error :: unauthorized_error ( context ) )
}
}
# [ middleware_fn ]
async fn ping ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
context . body ( "pong" ) ;
Ok ( context )
}
.. .
app . get ( "/ping" , m ! [ ip_guard , plaintext ] ) ;
.. .Un peu plus direct est sympa!
Si vous êtes aussi loin, merci d'avoir lu! N'hésitez pas à tendre la main.