rusthyperrust-axum

What happens in axum when a header is missing for a handler capturing a typed header?


axum allows me to capture http headers in a handler with the TypedHeader struct. For example:

async fn handler(TypedHeader(if_none_match): TypedHeader<IfNoneMatch>) -> String {
    let etag = "foo".parse::<ETag>().unwrap();
    if if_none_match.precondition_passes(&etag) {
        String::from("success")
    } else {
        String::from("failure")
    }
}

Now I'm wondering what happens if I get a request where the If-None-Match header is missing. With some debugging, I found out that the handler will still be called and the precondition will pass. However, I'm wondering what the instance of IfNoneMatch is now which I'm receiving? How is axum setting this instance and how can I determine whether the header was originally missing? I used the If-None-Match http header as an example here, but I would be interested in a general answer.


Solution

  • If a TypedHeader fails to extract from the request, it will reject the request and return a 400 status code and error message in the body by default.

    If you want to handle the case where a TypedHeader cannot be extracted, you can wrap it in an Option:

    async fn handler(maybe_if_none_match: Option<TypedHeader<IfNoneMatch>>) -> String {
    
    }
    

    The value will be Some if the extraction was successful and None otherwise.

    However, a TypedHeader may fail to be extracted due to an incorrectly encoded value. You may still wish to distinguish that case and if so you can wrap it in a Result:

    async fn handler(maybe_if_none_match: Result<TypedHeader<IfNoneMatch>, TypedHeaderRejection>) -> String {
    
    }
    

    The error type needs to match the rejection type of the FromRequestParts implementation. Clearly the value will be Ok if the extraction was successful and Err otherwise with the error value.

    This technique works for any extractor.