Add serialization for JSON and form bodies in post (#4764)

* Add serialization for JSON and form bodies in `post`

* Reuse code from `to json` instead of duplicating

* Fix formatting. Oops
This commit is contained in:
Genna Wingert 2022-03-07 17:49:45 +01:00 committed by GitHub
parent a2723c2ba4
commit 0a95bc7e60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 3 deletions

View File

@ -57,7 +57,7 @@ quick-xml = "0.22"
rand = "0.8" rand = "0.8"
rayon = "1.5.1" rayon = "1.5.1"
regex = "1.5.4" regex = "1.5.4"
reqwest = {version = "0.11", features = ["blocking"] } reqwest = {version = "0.11", features = ["blocking", "json"] }
roxmltree = "0.14.0" roxmltree = "0.14.0"
rust-embed = "6.3.0" rust-embed = "6.3.0"
serde = { version="1.0.123", features=["derive"] } serde = { version="1.0.123", features=["derive"] }

View File

@ -22,3 +22,5 @@ pub use nuon::ToNuon;
pub use tsv::ToTsv; pub use tsv::ToTsv;
pub use xml::ToXml; pub use xml::ToXml;
pub use yaml::ToYaml; pub use yaml::ToYaml;
pub(crate) use json::value_to_json_value;

View File

@ -1,3 +1,4 @@
use crate::formats::value_to_json_value;
use base64::encode; use base64::encode;
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
@ -98,6 +99,11 @@ impl Command for SubCommand {
example: "post -H [my-header-key my-header-value] url.com", example: "post -H [my-header-key my-header-value] url.com",
result: None, 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<String>, content_type: Option<String>,
content_length: Option<String>, content_length: Option<String>,
} }
#[derive(PartialEq, Eq)]
enum BodyType {
Json,
Form,
Unknown,
}
fn run_post( fn run_post(
engine_state: &EngineState, engine_state: &EngineState,
stack: &mut Stack, stack: &mut Stack,
@ -127,8 +141,8 @@ fn run_post(
user: call.get_flag(engine_state, stack, "user")?, user: call.get_flag(engine_state, stack, "user")?,
password: call.get_flag(engine_state, stack, "password")?, password: call.get_flag(engine_state, stack, "password")?,
insecure: call.get_flag(engine_state, stack, "insecure")?, insecure: call.get_flag(engine_state, stack, "insecure")?,
content_type: call.get_flag(engine_state, stack, "content_type")?, content_type: call.get_flag(engine_state, stack, "content-type")?,
content_length: call.get_flag(engine_state, stack, "content_length")?, content_length: call.get_flag(engine_state, stack, "content-length")?,
}; };
helper(engine_state, stack, call, args) helper(engine_state, stack, call, args)
} }
@ -178,6 +192,13 @@ fn helper(
(Some(user), _) => Some(encode(&format!("{}:", user))), (Some(user), _) => Some(encode(&format!("{}:", user))),
_ => None, _ => 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); let mut request = http_client(args.insecure.is_some()).post(location);
match body { match body {
Value::Binary { val, .. } => { Value::Binary { val, .. } => {
@ -186,6 +207,24 @@ fn helper(
Value::String { val, .. } => { Value::String { val, .. } => {
request = request.body(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::<Result<Vec<(String, String)>, ShellError>>()?;
request = request.form(&data)
}
_ => { _ => {
return Err(ShellError::IOError("unsupported body input".into())); return Err(ShellError::IOError("unsupported body input".into()));
} }