Routing
Route registration
All the routes exposed by your API must be registered with its Blueprint
.
In the snippet below you can see the registration of the GET /api/ping
route, the one you targeted with your curl
request.
// [...]
use pavex::blueprint::{router::GET, Blueprint};
use pavex::f;
pub fn register(bp: &mut Blueprint) {
bp.route(GET, "/api/ping", f!(self::ping::get));
}
It specifies:
- The HTTP method (
GET
) - The path (
/api/ping
) - An unambiguous path to the handler function (
self::ping::get
), wrapped in thef!
macro
Request handlers
The ping
function is the handler for the GET /api/ping
route:
use pavex::http::StatusCode;
/// Respond with a `200 OK` status code to indicate that the server is alive
/// and ready to accept new requests.
pub fn get() -> StatusCode {
StatusCode::OK
}
It's a public function that returns a StatusCode
.
StatusCode
is a valid response type for a Pavex handler since it implements
the IntoResponse
trait:
the framework
knows how to convert it into a "full" Response
object.
Add a new route
The ping
function is fairly boring: it doesn't take any arguments, and it always returns the same response.
Let's spice things up with a new route: GET /api/greet/:name
.
It takes a dynamic route parameter (name
) and we want it to return a success response with Hello, {name}
as its
body.
Create a new module, greet.rs
, in the app/src/routes
folder:
The body of the GET /api/greet/:name
handler is stubbed out with todo!()
for now, but we'll fix that soon enough.
Let's register the new route with the Blueprint
in the meantime:
// [...]
pub fn register(bp: &mut Blueprint) {
bp.route(GET, "/api/ping", f!(self::ping::get));
bp.route(GET, "/api/greet/:name", f!(self::greet::get)); // (1)!
}
- Dynamic path parameters are prefixed with a colon (
:
).
Extract path parameters
To access the name
route parameter from your new handler you must use the PathParams
extractor:
use pavex::request::path::PathParams;
use pavex::response::Response;
#[PathParams]
pub struct GreetParams {
pub name: String, /* (1)! */
}
pub fn get(params: PathParams<GreetParams> /* (2)! */) -> Response {
todo!()
}
- The name of the field must match the name of the route parameter as it appears in the path we registered with
the
Blueprint
. - The
PathParams
extractor is generic over the type of the path parameters.
In this case, we're using theGreetParams
type we just defined.
You can now return the expected response from the handler:
use pavex::request::path::PathParams;
use pavex::response::Response;
#[PathParams]
pub struct GreetParams {
pub name: String,
}
pub fn get(params: PathParams<GreetParams>) -> Response {
let GreetParams { name }/* (1)! */ = params.0;
Response::ok() // (2)!
.set_typed_body(format!("Hello, {name}!")) // (3)!
}
- This is an example of Rust's destructuring syntax.
Response
has a convenient constructor for each HTTP status code:Response::ok
starts building aResponse
with a200 OK
status code.set_typed_body
sets the body of the response and automatically infers a suitable value for theContent-Type
header based on the response body type.
Does it work? Only one way to find out!
Re-launch the application and issue a new request: (1)
- Remember to use
cargo px run
instead ofcargo run
!
You should see Hello, Ursula!
in your terminal if everything went well.