use typeway_core::*;
use typeway_macros::*;
use typeway_server::*;
struct BearerToken(String);
impl FromRequestParts for BearerToken {
type Error = JsonError;
fn from_request_parts(parts: &http::request::Parts) -> Result<Self, Self::Error> {
let header = parts
.headers
.get(http::header::AUTHORIZATION)
.ok_or_else(|| JsonError::unauthorized("missing Authorization header"))?
.to_str()
.map_err(|_| JsonError::bad_request("invalid Authorization header"))?;
let token = header
.strip_prefix("Bearer ")
.ok_or_else(|| JsonError::unauthorized("expected Bearer token"))?;
Ok(BearerToken(token.to_string()))
}
}
struct RawBody(String);
impl FromRequest for RawBody {
type Error = (http::StatusCode, String);
async fn from_request(
_parts: &http::request::Parts,
body: bytes::Bytes,
) -> Result<Self, Self::Error> {
String::from_utf8(body.to_vec()).map(RawBody).map_err(|e| {
(
http::StatusCode::BAD_REQUEST,
format!("invalid UTF-8 body: {e}"),
)
})
}
}
typeway_path!(type HelloPath = "hello");
typeway_path!(type EchoPath = "echo");
type API = (
GetEndpoint<HelloPath, String>,
PostEndpoint<EchoPath, String, String>,
);
async fn hello(token: BearerToken) -> String {
format!("Authenticated with token: {}", token.0)
}
async fn echo(_token: BearerToken, body: RawBody) -> String {
format!("Echo: {}", body.0)
}
#[tokio::main]
async fn main() {
let server = Server::<API>::new((bind::<_, _, _>(hello), bind::<_, _, _>(echo)));
println!("Custom extractors example on http://127.0.0.1:3000");
println!(" GET /hello - requires Bearer token");
println!(" POST /echo - requires Bearer token, echoes body");
server
.serve("127.0.0.1:3000".parse().unwrap())
.await
.unwrap();
}