fhttp-core 1.4.0

core library for the fhttp tool
Documentation
use crate::parsers::Request;
use crate::request_def::body::Body;

pub trait Curl {
    fn curl(&self) -> String;
}

impl Curl for Request {
    fn curl(&self) -> String {
        let mut parts = vec![
            format!("curl -X {}", self.method.as_str()),
        ];

        for (name, value) in self.headers.iter() {
            parts.push(format!(
                "-H \"{}: {}\"",
                name.as_str().replace(r#"""#, r#"\""#),
                value.to_str().unwrap().replace(r#"""#, r#"\""#)
            ))
        }

        match &self.body {
            Body::Plain(body) => if !body.is_empty() {
                parts.push(format!(
                    "-d \"{}\"",
                    escape_body(body)
                ));
            },
            Body::Files(files) => for file in files {
                parts.push(format!(
                    "-F \"{}=@{}\"",
                    file.name.replace(r#"""#, r#"\""#),
                    file.path.to_str().replace(r#"""#, r#"\""#)
                ));
            },
        }

        parts.push(format!("--url \"{}\"", &self.url.replace(r#"""#, r#"\""#)));

        parts.join(" \\\n")
    }
}

fn escape_body<S: Into<String>>(input: S) -> String {
    input.into()
        .replace("\n", "\\\n")
        .replace("\"", "\\\"")
}

#[cfg(test)]
mod test {
    use indoc::{indoc, formatdoc};

    use crate::test_utils::root;

    use serde_json::json;

    use super::*;

    #[test]
    fn should_print_command_for_simple_request() {
        let result = Request::basic("GET", "http://localhost/123")
            .curl();

        assert_eq!(
            result,
            indoc!(r#"
                curl -X GET \
                --url "http://localhost/123""#
            )
        );
    }

    #[test]
    fn should_print_command_with_headers() {
        let result = Request::basic("GET", "http://localhost/123")
            .add_header("accept", "application/json")
            .add_header("content-type", "application/json")
            .curl();

        assert_eq!(
            result,
            indoc!(r#"
                curl -X GET \
                -H "accept: application/json" \
                -H "content-type: application/json" \
                --url "http://localhost/123""#
            )
        );
    }

    #[test]
    fn should_print_command_with_headers_and_body() {
        let body = "{\n    \"foo\": \"bar\",\n    \"bar\": \"escape'me\"\n}";

        let result = Request::basic("GET", "http://localhost/555")
            .add_header("content-type", "application/json")
            .body(&body)
            .curl();

        assert_eq!(
            result,
            indoc!(r#"
                curl -X GET \
                -H "content-type: application/json" \
                -d "{\
                    \"foo\": \"bar\",\
                    \"bar\": \"escape'me\"\
                }" \
                --url "http://localhost/555""#
            )
        );
    }

    #[test]
    fn should_print_command_with_plain_text_body() {
        let result = Request::basic("GET", "http://localhost/555")
            .add_header("content-type", "application/json")
            .body("this is a so-called \"test\"")
            .curl();

        assert_eq!(
            result,
            indoc!(r#"
                curl -X GET \
                -H "content-type: application/json" \
                -d "this is a so-called \"test\"" \
                --url "http://localhost/555""#
            )
        );
    }

    #[test]
    fn should_print_command_with_body_with_newlines() {
        let result = Request::basic("GET", "http://localhost/555")
            .add_header("content-type", "application/json")
            .body("one\ntwo\nthree")
            .curl();

        assert_eq!(
            result,
            indoc!(r#"
                curl -X GET \
                -H "content-type: application/json" \
                -d "one\
                two\
                three" \
                --url "http://localhost/555""#
            )
        );
    }

    #[test]
    fn should_print_command_with_gql_body() {
        let result = Request::basic("GET", "http://localhost/555")
            .add_header("content-type", "application/json")
            .gql_body(
                json!({
                    "query": "query { search(filter: \"foobar\") { id } }",
                })
            )
            .curl();

        assert_eq!(
            result,
            indoc!(r#"
                curl -X GET \
                -H "content-type: application/json" \
                -d "{\"query\":\"query { search(filter: \\"foobar\\") { id } }\"}" \
                --url "http://localhost/555""#
            )
        );
    }

    #[test]
    fn should_print_command_with_headers_and_files() {
        let result = Request::basic("GET", "http://localhost/555")
            .add_header("content-type", "application/json")
            .file_body(&[
                ("file1", "resources/it/profiles.json"),
                ("file2", "resources/it/profiles2.json"),
            ])
            .curl();

        assert_eq!(
            result,
            formatdoc!(r#"
                curl -X GET \
                -H "content-type: application/json" \
                -F "file1=@{base}/resources/it/profiles.json" \
                -F "file2=@{base}/resources/it/profiles2.json" \
                --url "http://localhost/555""#,
                base = root().to_str().to_string(),
            )
        );
    }
}