diff --git a/crates/nu-command/Cargo.toml b/crates/nu-command/Cargo.toml index 2413d6caa7..86556edf04 100644 --- a/crates/nu-command/Cargo.toml +++ b/crates/nu-command/Cargo.toml @@ -57,7 +57,7 @@ quick-xml = "0.22" rand = "0.8" rayon = "1.5.1" regex = "1.5.4" -reqwest = {version = "0.11", features = ["blocking"] } +reqwest = {version = "0.11", features = ["blocking", "json"] } roxmltree = "0.14.0" rust-embed = "6.3.0" serde = { version="1.0.123", features=["derive"] } diff --git a/crates/nu-command/src/formats/to/mod.rs b/crates/nu-command/src/formats/to/mod.rs index 22c86f8585..bc693e481f 100644 --- a/crates/nu-command/src/formats/to/mod.rs +++ b/crates/nu-command/src/formats/to/mod.rs @@ -22,3 +22,5 @@ pub use nuon::ToNuon; pub use tsv::ToTsv; pub use xml::ToXml; pub use yaml::ToYaml; + +pub(crate) use json::value_to_json_value; diff --git a/crates/nu-command/src/network/post.rs b/crates/nu-command/src/network/post.rs index 4cd32aef4a..afc6dfd5af 100644 --- a/crates/nu-command/src/network/post.rs +++ b/crates/nu-command/src/network/post.rs @@ -1,3 +1,4 @@ +use crate::formats::value_to_json_value; use base64::encode; use nu_engine::CallExt; use nu_protocol::ast::Call; @@ -98,6 +99,11 @@ impl Command for SubCommand { example: "post -H [my-header-key my-header-value] url.com", result: None, }, + Example { + description: "Post content to url.com with a json body", + example: "post -t application/json url.com { field: value }", + result: None, + }, ] } } @@ -113,6 +119,14 @@ struct Arguments { content_type: Option, content_length: Option, } + +#[derive(PartialEq, Eq)] +enum BodyType { + Json, + Form, + Unknown, +} + fn run_post( engine_state: &EngineState, stack: &mut Stack, @@ -127,8 +141,8 @@ fn run_post( user: call.get_flag(engine_state, stack, "user")?, password: call.get_flag(engine_state, stack, "password")?, insecure: call.get_flag(engine_state, stack, "insecure")?, - content_type: call.get_flag(engine_state, stack, "content_type")?, - content_length: call.get_flag(engine_state, stack, "content_length")?, + content_type: call.get_flag(engine_state, stack, "content-type")?, + content_length: call.get_flag(engine_state, stack, "content-length")?, }; helper(engine_state, stack, call, args) } @@ -178,6 +192,13 @@ fn helper( (Some(user), _) => Some(encode(&format!("{}:", user))), _ => None, }; + + let body_type = match &args.content_type { + Some(it) if it == "application/json" => BodyType::Json, + Some(it) if it == "application/x-www-form-urlencoded" => BodyType::Form, + _ => BodyType::Unknown, + }; + let mut request = http_client(args.insecure.is_some()).post(location); match body { Value::Binary { val, .. } => { @@ -186,6 +207,24 @@ fn helper( Value::String { val, .. } => { request = request.body(val); } + Value::Record { .. } if body_type == BodyType::Json => { + let data = value_to_json_value(&body)?; + request = request.json(&data); + } + Value::Record { .. } if body_type == BodyType::Form => { + let data = value_to_json_value(&body)?; + request = request.form(&data); + } + Value::List { vals, .. } if body_type == BodyType::Form => { + if vals.len() % 2 != 0 { + return Err(ShellError::IOError("unsupported body input".into())); + } + let data = vals + .chunks(2) + .map(|it| Ok((it[0].as_string()?, it[1].as_string()?))) + .collect::, ShellError>>()?; + request = request.form(&data) + } _ => { return Err(ShellError::IOError("unsupported body input".into())); }