From 3df0177ba56dfb17284d40cf104b5df088b0ead6 Mon Sep 17 00:00:00 2001 From: Noah Date: Sat, 14 Jun 2025 09:22:37 +0200 Subject: [PATCH] feat: use get request by default, post if payload (#15862) Hello, this PR resolves the second request of the issue https://github.com/nushell/nushell/issues/10957, which involves using a default verb based on the request. If a URL is provided, the command will default to GET, and if data is provided, it will default to POST. This means that the following pairs of commands are equivalent: ``` http --content-type application/json http://localhost:8000 {a:1} http post --content-type application/json http://localhost:8000 {a:1} ``` ``` http http://localhost:8000 "username" http post http://localhost:8000 "username" ``` ``` http http://localhost:8000 http get http://localhost:8000 ``` The `http` command now accepts all flags of the `post` and `get` commands. It will still display the help message if no subcommand is provided, and the description has been updated accordingly. The logic in the `http` command is minimal to delegate error management responsibilities to the specific `run_get` and `run_post` functions. --- crates/nu-command/src/network/http/get.rs | 2 +- crates/nu-command/src/network/http/http_.rs | 113 +++++++++++++++++++- crates/nu-command/src/network/http/post.rs | 2 +- 3 files changed, 111 insertions(+), 6 deletions(-) diff --git a/crates/nu-command/src/network/http/get.rs b/crates/nu-command/src/network/http/get.rs index b8fc181f7e..39b2d6a7f9 100644 --- a/crates/nu-command/src/network/http/get.rs +++ b/crates/nu-command/src/network/http/get.rs @@ -141,7 +141,7 @@ struct Arguments { redirect: Option>, } -fn run_get( +pub fn run_get( engine_state: &EngineState, stack: &mut Stack, call: &Call, diff --git a/crates/nu-command/src/network/http/http_.rs b/crates/nu-command/src/network/http/http_.rs index a797054ced..9b6eab9e8e 100644 --- a/crates/nu-command/src/network/http/http_.rs +++ b/crates/nu-command/src/network/http/http_.rs @@ -1,5 +1,8 @@ use nu_engine::{command_prelude::*, get_full_help}; +use super::get::run_get; +use super::post::run_post; + #[derive(Clone)] pub struct Http; @@ -10,7 +13,76 @@ impl Command for Http { fn signature(&self) -> Signature { Signature::build("http") - .input_output_types(vec![(Type::Nothing, Type::String)]) + .input_output_types(vec![(Type::Nothing, Type::Any)]) + // common to get more than help. Get by default + .optional( + "URL", + SyntaxShape::String, + "The URL to fetch the contents from.", + ) + // post + .optional( + "data", + SyntaxShape::Any, + "The contents of the post body. Required unless part of a pipeline.", + ) + .named( + "content-type", + SyntaxShape::Any, + "the MIME type of content to post", + Some('t'), + ) + // common + .named( + "user", + SyntaxShape::Any, + "the username when authenticating", + Some('u'), + ) + .named( + "password", + SyntaxShape::Any, + "the password when authenticating", + Some('p'), + ) + .named( + "max-time", + SyntaxShape::Duration, + "max duration before timeout occurs", + Some('m'), + ) + .named( + "headers", + SyntaxShape::Any, + "custom headers you want to add ", + Some('H'), + ) + .switch( + "raw", + "fetch contents as text rather than a table", + Some('r'), + ) + .switch( + "insecure", + "allow insecure server connections when using SSL", + Some('k'), + ) + .switch( + "full", + "returns the full response instead of only the body", + Some('f'), + ) + .switch( + "allow-errors", + "do not fail if the server returns an error code", + Some('e'), + ) + .named( + "redirect-mode", + SyntaxShape::String, + "What to do when encountering redirects. Default: 'follow'. Valid options: 'follow' ('f'), 'manual' ('m'), 'error' ('e').", + Some('R') + ) .category(Category::Network) } @@ -19,7 +91,7 @@ impl Command for Http { } fn extra_description(&self) -> &str { - "You must use one of the following subcommands. Using this command as-is will only produce this help message." + "Without a subcommand but with a URL provided, it performs a GET request by default or a POST request if data is provided. You can use one of the following subcommands. Using this command as-is will only display this help message." } fn search_terms(&self) -> Vec<&str> { @@ -33,8 +105,41 @@ impl Command for Http { engine_state: &EngineState, stack: &mut Stack, call: &Call, - _input: PipelineData, + input: PipelineData, ) -> Result { - Ok(Value::string(get_full_help(self, engine_state, stack), call.head).into_pipeline_data()) + let url = call.opt::(engine_state, stack, 0)?; + let data = call.opt::(engine_state, stack, 1)?; + match (url.is_some(), data.is_some()) { + (true, true) => run_post(engine_state, stack, call, input), + (true, false) => run_get(engine_state, stack, call, input), + (false, true) => Err(ShellError::NushellFailed { + msg: (String::from("Default verb is get with a payload. Impossible state")), + }), + (false, false) => Ok(Value::string( + get_full_help(self, engine_state, stack), + call.head, + ) + .into_pipeline_data()), + } + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Get content from example.com with default verb", + example: "http https://www.example.com", + result: None, + }, + Example { + description: "Post content to example.com with default verb", + example: "http https://www.example.com 'body'", + result: None, + }, + Example { + description: "Get content from example.com with explicit verb", + example: "http get https://www.example.com", + result: None, + }, + ] } } diff --git a/crates/nu-command/src/network/http/post.rs b/crates/nu-command/src/network/http/post.rs index 03fa0bf984..7bc8798753 100644 --- a/crates/nu-command/src/network/http/post.rs +++ b/crates/nu-command/src/network/http/post.rs @@ -161,7 +161,7 @@ struct Arguments { redirect: Option>, } -fn run_post( +pub fn run_post( engine_state: &EngineState, stack: &mut Stack, call: &Call,