Beginnen Sie mit Beispielen und Walkthroughs auf unserer Website!
Haben Sie keine Zeit, die Dokumente zu lesen? Kasse
✅ läuft in stabil ✅ läuft schnell ✅ verwendet nicht unsicher
Dokumentation
Thruster ist ein Web -Framework, der darauf abzielt, dass Entwickler produktiv und konsistent über Projekte und Teams hinweg sind. Seine Ziele sind:
Durchmesser auch
unsafeThruster kann mit unterschiedlichen Server -Backends ausgeführt werden und stellt eine schön verpackte Ebene darüber dar. Dies bedeutet, dass es mit den neuesten und größten Veränderungen von Hyper, Actix oder sogar Thrusterserver, einem einheimischen HTTP-Motor, Schritt halten kann.
Basierend auf Frameworks wie KOA und Express zielt Thruster ein Vergnügen, sich zu entwickeln.
Um den Beispiel cargo run --example <example-name> . Zum Beispiel cargo run --example hello_world und öffnen Sie http: // localhost: 4321/
Die Kernteile, die das neue Async -Wartearbeiten auf den Code warten lassen, werden Middleware -Funktionen mit dem Attribut #[middleware_fn] (das die Middleware so markiert, dass sie mit der stabilen Futures -Version, auf der Thruster aufgebaut ist, kompatibel ist) und dann mit der M -Middle -Futh -Version) und dann mit der M -Markierung) und dann mit der m! Makro in den tatsächlichen Routen.
Ein einfaches Beispiel für die Verwendung von Async -Warten ist:
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 ;
}Hier ist ein schönes Beispiel
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 ;
} Thruster bietet eine einfache Testsuite, um Ihre Endpunkte zu testen. Fügen Sie einfach das testing nach unten ein:
let mut app = App :: < Request , Ctx , ( ) > :: new_basic ( ) ;
.. .
app . get ( "/plaintext" , m ! [ plaintext ] ) ;
.. .
let result = testing :: get ( app , "/plaintext" ) ;
assert ! ( result . body == "Hello, World!" ) ; Middleware ist super einfach zu machen! Erstellen Sie einfach eine Funktion und exportieren Sie sie auf Modulebene. Im Folgenden sehen Sie ein Stück Middleware, mit dem die Profilierung von Anfragen ermöglicht wird:
# [ 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 )
}Möglicherweise möchten Sie spezifischere Daten zulassen, die im Kontext gespeichert sind. Zum Beispiel möchten Sie möglicherweise die Parameter von Abfragen in eine HashMap für die spätere Verwendung durch andere Middlewares hydratieren können. Um dies zu tun, können Sie ein zusätzliches Merkmal für den Kontext erstellen, an den Middlewares stromabwärts halten muss. Schauen Sie sich die bereitgestellte Query_Params Middleware an, um ein Beispiel zu erhalten.
Thruster ist in der Lage, die Routing -Ebene nur auf einem Server zu stellen, beispielsweise im obigen Hyper -Snippet. Dies kann weitgehend auf jedes Backend angewendet werden, solange der Server ThrusterServer implementiert.
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 ) ;
}Es muss geben:
In der build -Funktion sollte die Server -Implementierung:
let matched = app.resolve_from_method_and_path(<some method>, <some path>); (Dies liefert das tatsächliche Routing.)app.resolve(<incoming request>, matched) (Dies führt die gekettete Middleware aus.) 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 ) ;
.. .Hier ist Thruster:
# [ 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 ] ) ;
.. .Ein bisschen direkter ist schön!
Wenn Sie so weit gekommen sind, danke fürs Lesen! Fühlen Sie sich immer frei zu erreichen.