Use pipeline data for http post|put|patch|delete commands. (#13254)

# Description
Provides the ability to use http commands as part of a pipeline.
Additionally, this pull requests extends the pipeline metadata to add a
content_type field. The content_type metadata field allows commands such
as `to json` to set the metadata in the pipeline allowing the http
commands to use it when making requests.

This pull request also introduces the ability to directly stream http
requests from streaming pipelines.

One other small change is that Content-Type will always be set if it is
passed in to the http commands, either indirectly or throw the content
type flag. Previously it was not preserved with requests that were not
of type json or form data.

# User-Facing Changes
* `http post`, `http put`, `http patch`, `http delete` can be used as
part of a pipeline
* `to text`, `to json`, `from json` all set the content_type metadata
field and the http commands will utilize them when making requests.
This commit is contained in:
Jack Wright
2024-07-01 12:34:19 -07:00
committed by GitHub
parent e5cf4863e9
commit 0d060aeae8
24 changed files with 466 additions and 120 deletions

View File

@ -1,5 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::ast::PathMember;
use nu_protocol::{ast::PathMember, PipelineMetadata};
#[derive(Clone)]
pub struct ToJson;
@ -61,7 +61,12 @@ impl Command for ToJson {
match json_result {
Ok(serde_json_string) => {
Ok(Value::string(serde_json_string, span).into_pipeline_data())
let res = Value::string(serde_json_string, span);
let metadata = PipelineMetadata {
data_source: nu_protocol::DataSource::None,
content_type: Some("application/json".to_string()),
};
Ok(PipelineData::Value(res, Some(metadata)))
}
_ => Ok(Value::error(
ShellError::CantConvert {

View File

@ -1,6 +1,8 @@
use chrono_humanize::HumanTime;
use nu_engine::command_prelude::*;
use nu_protocol::{format_duration, format_filesize_from_conf, ByteStream, Config};
use nu_protocol::{
format_duration, format_filesize_from_conf, ByteStream, Config, PipelineMetadata,
};
const LINE_ENDING: &str = if cfg!(target_os = "windows") {
"\r\n"
@ -37,10 +39,14 @@ impl Command for ToText {
let input = input.try_expand_range()?;
match input {
PipelineData::Empty => Ok(Value::string(String::new(), span).into_pipeline_data()),
PipelineData::Empty => Ok(Value::string(String::new(), span)
.into_pipeline_data_with_metadata(update_metadata(None))),
PipelineData::Value(value, ..) => {
let str = local_into_string(value, LINE_ENDING, engine_state.get_config());
Ok(Value::string(str, span).into_pipeline_data())
Ok(
Value::string(str, span)
.into_pipeline_data_with_metadata(update_metadata(None)),
)
}
PipelineData::ListStream(stream, meta) => {
let span = stream.span();
@ -57,10 +63,12 @@ impl Command for ToText {
engine_state.ctrlc.clone(),
ByteStreamType::String,
),
meta,
update_metadata(meta),
))
}
PipelineData::ByteStream(stream, meta) => Ok(PipelineData::ByteStream(stream, meta)),
PipelineData::ByteStream(stream, meta) => {
Ok(PipelineData::ByteStream(stream, update_metadata(meta)))
}
}
}
@ -124,6 +132,14 @@ fn local_into_string(value: Value, separator: &str, config: &Config) -> String {
}
}
fn update_metadata(metadata: Option<PipelineMetadata>) -> Option<PipelineMetadata> {
metadata
.map(|md| md.with_content_type(Some("text/plain".to_string())))
.or_else(|| {
Some(PipelineMetadata::default().with_content_type(Some("text/plain".to_string())))
})
}
#[cfg(test)]
mod test {
use super::*;