pub struct Call { /* private fields */ }Expand description
Per-request context: the single object a handler receives (Ktor-style).
A Call bundles the request method, URI, headers, captured path
parameters, the (buffered) body, a handle to shared application
state, and a per-call extension map. Handlers receive it
either directly (|c: Call| async { ... }) or indirectly through
extractors such as Path and
Query, which read from the Call for you.
Read-only accessors (method, uri,
path, header, query,
param) borrow &self; body consumption
(receive_bytes, receive_text)
takes &mut self. The insert/get pair
passes typed values between middleware and downstream handlers.
Construct one with Call::new in unit tests; in production the engine and
the TestClient build it for you.
use churust_core::Call;
use http::{HeaderMap, Method};
use bytes::Bytes;
let call = Call::new(
Method::GET,
"/search?q=rust".parse().unwrap(),
HeaderMap::new(),
Bytes::new(),
);
assert_eq!(call.method(), &Method::GET);
assert_eq!(call.path(), "/search");
assert_eq!(call.query("q").as_deref(), Some("rust"));Implementations§
Source§impl Call
impl Call
Sourcepub fn new(method: Method, uri: Uri, headers: HeaderMap, body: Bytes) -> Self
pub fn new(method: Method, uri: Uri, headers: HeaderMap, body: Bytes) -> Self
Construct a Call from already-parsed request parts (used by the engine and the test harness alike).
Sourcepub fn header(&self, name: &str) -> Option<&str>
pub fn header(&self, name: &str) -> Option<&str>
The value of header name as a UTF-8 string, or None if the header is
absent or its value is not valid UTF-8. Header name matching is
case-insensitive.
use churust_core::Call;
use http::{HeaderMap, Method, header::ACCEPT, HeaderValue};
use bytes::Bytes;
let mut headers = HeaderMap::new();
headers.insert(ACCEPT, HeaderValue::from_static("application/json"));
let call = Call::new(Method::GET, "/".parse().unwrap(), headers, Bytes::new());
assert_eq!(call.header("accept"), Some("application/json"));
assert_eq!(call.header("x-missing"), None);Sourcepub fn query_string(&self) -> &str
pub fn query_string(&self) -> &str
The raw query string with the leading ? stripped, or "" if there is
none. To deserialize the whole query into a struct, prefer the
Query extractor.
use churust_core::Call;
use http::{HeaderMap, Method};
use bytes::Bytes;
let call = Call::new(Method::GET, "/s?a=1&b=2".parse().unwrap(), HeaderMap::new(), Bytes::new());
assert_eq!(call.query_string(), "a=1&b=2");Sourcepub fn query(&self, key: &str) -> Option<String>
pub fn query(&self, key: &str) -> Option<String>
The first value for query key key, percent- and +-decoded, or None
if the key is absent.
use churust_core::Call;
use http::{HeaderMap, Method};
use bytes::Bytes;
let call = Call::new(Method::GET, "/s?q=hello+world".parse().unwrap(), HeaderMap::new(), Bytes::new());
assert_eq!(call.query("q").as_deref(), Some("hello world"));
assert_eq!(call.query("missing"), None);Sourcepub fn state<T: Send + Sync + 'static>(&self) -> Option<Arc<T>>
pub fn state<T: Send + Sync + 'static>(&self) -> Option<Arc<T>>
A shared handle to application state of type T, or None if no value
of that type was registered with
AppBuilder::state. For handler arguments,
the State extractor is usually more convenient.
use churust_core::{Churust, Call, TestClient};
#[derive(Clone)]
struct AppName(&'static str);
let app = Churust::server()
.state(AppName("churust"))
.routing(|r| {
r.get("/", |c: Call| async move {
format!("app={}", c.state::<AppName>().unwrap().0)
});
})
.build();
let res = TestClient::new(app).get("/").send().await;
assert_eq!(res.text(), "app=churust");Sourcepub fn params_iter(&self) -> impl Iterator<Item = (&str, &str)>
pub fn params_iter(&self) -> impl Iterator<Item = (&str, &str)>
Iterate over the captured path parameters as (name, value) pairs.
Iteration order is unspecified (the parameters are stored in a hash map).
Sourcepub fn param_raw(&self, name: &str) -> Option<&str>
pub fn param_raw(&self, name: &str) -> Option<&str>
The raw, unparsed value of path parameter name, or None if the route
has no such parameter. Use param to parse it into a
typed value.
Sourcepub fn param<T>(&self, name: &str) -> Result<T>
pub fn param<T>(&self, name: &str) -> Result<T>
Parse path parameter name into T.
Returns a 400 Bad Request Error if the parameter is
missing or fails to parse.
use churust_core::{Churust, Call, TestClient};
let app = Churust::server()
.routing(|r| {
r.get("/users/{id}", |c: Call| async move {
let id: u64 = c.param("id")?;
Ok::<_, churust_core::Error>(format!("user {id}"))
});
})
.build();
let res = TestClient::new(app).get("/users/42").send().await;
assert_eq!(res.text(), "user 42");Sourcepub async fn receive_bytes(&mut self) -> Bytes
pub async fn receive_bytes(&mut self) -> Bytes
Take the request body as raw Bytes, leaving the call’s body empty.
This consumes the body: a second call returns an empty buffer. It is
async to leave room for future streaming bodies.
use churust_core::Call;
use http::{HeaderMap, Method};
use bytes::Bytes;
let mut call = Call::new(Method::POST, "/".parse().unwrap(), HeaderMap::new(), Bytes::from("data"));
assert_eq!(&call.receive_bytes().await[..], b"data");
assert!(call.receive_bytes().await.is_empty()); // already consumedSourcepub async fn receive_text(&mut self) -> Result<String>
pub async fn receive_text(&mut self) -> Result<String>
Take the request body decoded as UTF-8, consuming it.
Returns a 400 Bad Request Error if the body is not
valid UTF-8.
use churust_core::Call;
use http::{HeaderMap, Method};
use bytes::Bytes;
let mut call = Call::new(Method::POST, "/".parse().unwrap(), HeaderMap::new(), Bytes::from("ping"));
assert_eq!(call.receive_text().await.unwrap(), "ping");Sourcepub fn insert<T: Clone + Send + Sync + 'static>(&mut self, value: T)
pub fn insert<T: Clone + Send + Sync + 'static>(&mut self, value: T)
Insert a per-call typed value into the call’s extension map, keyed by its
type. Typically used by a middleware to attach context (e.g. an
authenticated principal) that a downstream extractor or handler reads via
get. Inserting a second value of the same type replaces
the first.
use churust_core::Call;
use http::{HeaderMap, Method};
use bytes::Bytes;
#[derive(Clone, PartialEq, Debug)]
struct UserId(u32);
let mut call = Call::new(Method::GET, "/".parse().unwrap(), HeaderMap::new(), Bytes::new());
call.insert(UserId(7));
assert_eq!(call.get::<UserId>(), Some(UserId(7)));Sourcepub fn get<T: Clone + Send + Sync + 'static>(&self) -> Option<T>
pub fn get<T: Clone + Send + Sync + 'static>(&self) -> Option<T>
Get a clone of the per-call value of type T previously stored with
insert, or None if none was stored.
use churust_core::Call;
use http::{HeaderMap, Method};
use bytes::Bytes;
let call = Call::new(Method::GET, "/".parse().unwrap(), HeaderMap::new(), Bytes::new());
assert_eq!(call.get::<u32>(), None);Sourcepub fn respond_text(&self, body: impl Into<String>) -> Response
pub fn respond_text(&self, body: impl Into<String>) -> Response
Build a 200 OK text/plain Response — a shorthand for
Response::text.
use churust_core::Call;
use http::{HeaderMap, Method};
use bytes::Bytes;
let call = Call::new(Method::GET, "/".parse().unwrap(), HeaderMap::new(), Bytes::new());
let res = call.respond_text("ok");
assert_eq!(res.body.as_slice(), Some(&b"ok"[..]));Sourcepub fn respond_status(&self, status: StatusCode) -> Response
pub fn respond_status(&self, status: StatusCode) -> Response
Build an empty-bodied Response with the given status — a shorthand
for Response::new.
use churust_core::Call;
use http::{HeaderMap, Method, StatusCode};
use bytes::Bytes;
let call = Call::new(Method::GET, "/".parse().unwrap(), HeaderMap::new(), Bytes::new());
assert_eq!(call.respond_status(StatusCode::ACCEPTED).status, StatusCode::ACCEPTED);