rjango 0.1.1

A full-stack Rust backend framework inspired by Django
Documentation
use axum::http::{
    HeaderMap, HeaderValue, Method,
    header::{CONTENT_LENGTH, CONTENT_TYPE},
};
use bytes::Bytes;

use crate::http::request::HttpRequest;

#[derive(Debug, Clone, Copy, Default)]
pub struct RequestFactory;

impl RequestFactory {
    #[must_use]
    pub fn new() -> Self {
        Self
    }

    #[must_use]
    pub fn get(&self, path: &str) -> HttpRequest {
        self.build_request(Method::GET, path, "")
    }

    #[must_use]
    pub fn post(&self, path: &str, data: impl AsRef<str>) -> HttpRequest {
        self.build_request(Method::POST, path, data.as_ref())
    }

    #[must_use]
    pub fn put(&self, path: &str) -> HttpRequest {
        self.build_request(Method::PUT, path, "")
    }

    #[must_use]
    pub fn delete(&self, path: &str) -> HttpRequest {
        self.build_request(Method::DELETE, path, "")
    }

    #[must_use]
    fn build_request(&self, method: Method, path: &str, body: &str) -> HttpRequest {
        let mut headers = HeaderMap::new();

        if !body.is_empty() {
            headers.insert(
                CONTENT_TYPE,
                HeaderValue::from_static("application/x-www-form-urlencoded"),
            );
            headers.insert(
                CONTENT_LENGTH,
                HeaderValue::from_str(&body.len().to_string())
                    .expect("request factory content length should be valid"),
            );
        }

        HttpRequest::from_axum(
            method,
            path.parse()
                .expect("request factory path should parse as URI"),
            headers,
            Bytes::copy_from_slice(body.as_bytes()),
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use axum::http::Method;

    #[test]
    fn test_request_factory_get_builds_correct_method() {
        let factory = RequestFactory::new();
        let request = factory.get("/articles/");

        assert_eq!(request.method, Method::GET);
        assert_eq!(request.path, "/articles/");
        assert_eq!(request.query_string, "");
        assert!(request.body().is_empty());
    }

    #[test]
    fn test_request_factory_post_sets_body() {
        let factory = RequestFactory::new();
        let request = factory.post("/submit/", "name=alice");

        assert_eq!(request.method, Method::POST);
        assert_eq!(request.body_str().expect("utf8 body"), "name=alice");
        assert_eq!(
            request.content_type.as_deref(),
            Some("application/x-www-form-urlencoded")
        );
        assert_eq!(request.meta.get("CONTENT_LENGTH"), Some(&"10".to_string()));
    }

    #[test]
    fn test_request_factory_with_query_string() {
        let factory = RequestFactory::new();
        let request = factory.get("/search/?page=2&tag=rust");

        assert_eq!(request.path, "/search/");
        assert_eq!(request.query_string, "page=2&tag=rust");
        assert_eq!(request.get_full_path(), "/search/?page=2&tag=rust");
    }

    #[test]
    fn request_factory_put_builds_empty_body_request() {
        let factory = RequestFactory::new();
        let request = factory.put("/items/42/");

        assert_eq!(request.method, Method::PUT);
        assert_eq!(request.path, "/items/42/");
        assert!(request.body().is_empty());
    }

    #[test]
    fn request_factory_delete_builds_empty_body_request() {
        let factory = RequestFactory::new();
        let request = factory.delete("/items/42/");

        assert_eq!(request.method, Method::DELETE);
        assert_eq!(request.path, "/items/42/");
        assert!(request.body().is_empty());
    }
}