diff --git a/README.md b/README.md index 400cf73..f218c31 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,15 @@ You can easily define your API requests and customize the output to extract spec The tool supports environment variables, allowing you to store sensitive data, such as API keys, securely. You can also pipe the stdin to your API Response with ${STDIN}. -## Example YAML Configuration +- [Example YAML Configuration](#example-yaml-configuration) +- [Usage Examples](#usage-examples) + - [Translate Text](#translate-text) + - [Generate Git Commit Message](#generate-git-commit-message) +- [YAML Attributes](#yaml-attributes) +- [Passing Arguments to httpcli Commands](#passing-arguments-to-httpcli-commands) +- [CLI Flags](#cli-flags) +## Example YAML Configuration Here's an example of a YAML configuration file that includes two different API requests: `gitdiff` and `translate`. ~/.httpcli.yaml ``` @@ -75,6 +82,22 @@ In your YAML configuration file, the following attributes can be used to define This structure allows you to easily define and customize your API requests within the YAML configuration file. +## Passing Arguments to httpcli Commands + +With `httpcli`, you can pass dynamic values to your commands using the `${ARG1}`, `${ARG2}`, and so on, placeholders in your YAML configuration file. These placeholders will be replaced with the respective command line arguments provided when invoking `httpcli`. + +For example, let's say you have a translation API configured in your YAML file, and you want to translate a given word or phrase in a target_lang. You can use the `${ARG1}` and `${ARG2}` placeholder in your YAML configuration to represent the text you want to translate: + +```yaml +translate: + url: "https://api.example.com/translate?text=${ARG1}&target_lang={ARG2}" + output: "translations[0].text" +``` +Now, when you call httpcli with the translate command and provide a text argument, the ${ARG1} placeholder will be replaced with the provided text: +``` +httpcli translate "A green Apple" fr +``` + ## CLI Flags `httpcli` supports various flags to customize its behavior and provide additional functionality. These flags can be passed along with the command to modify the tool's behavior: diff --git a/cmd/tpl.go b/cmd/tpl.go index 2948cc0..876ee96 100644 --- a/cmd/tpl.go +++ b/cmd/tpl.go @@ -34,7 +34,7 @@ func tplCommand(cmd *cobra.Command, args []string) error { return err } - output, err := fc.handleFunc(cmd) + output, err := fc.handleFunc(cmd, args) if err != nil { return err } @@ -72,8 +72,49 @@ func initFunctionConfig(cmd *cobra.Command, args []string) (FunctionConfig, erro return funcConfig, nil } -func (fc *FunctionConfig) handleFunc(cmd *cobra.Command) (string, error) { - jsonData, err := fc.getJSONData(cmd) +func (fc *FunctionConfig) replaceArgs(args []string) { + if len(args) <= 1 { + return + } + for i, arg := range args[:1] { + placeholder := fmt.Sprintf("${ARG%d}", i) + + fc.Url = strings.Replace(fc.Url, placeholder, arg, -1) + + for i, header := range fc.Header { + fc.Header[i] = strings.Replace(header, placeholder, arg, -1) + } + } +} + +func (fc *FunctionConfig) replaceEnvVariables() { + for _, env := range fc.Env { + fc.Url = strings.Replace(fc.Url, fmt.Sprintf("${%s}", env), os.Getenv(env), -1) + + for i, header := range fc.Header { + fc.Header[i] = strings.Replace(header, fmt.Sprintf("${%s}", env), os.Getenv(env), -1) + } + } +} + +func (fc *FunctionConfig) replaceVariables(cmd *cobra.Command, args []string, jsonData []byte) ([]byte, error) { + fc.replaceArgs(args) + fc.replaceEnvVariables() + + jsonData, err := util.ReplaceStdIn(jsonData) + if err != nil { + return nil, util.HandleError(cmd, err, util.REPLACE_STDIN_FAILED) + } + return util.ReplaceArgs(jsonData, args), nil +} + +func (fc *FunctionConfig) handleFunc(cmd *cobra.Command, args []string) (string, error) { + jsonData, err := fc.getJSONData(cmd, args) + if err != nil { + return "", err + } + + jsonData, err = fc.replaceVariables(cmd, args, jsonData) if err != nil { return "", err } @@ -92,15 +133,12 @@ func (fc *FunctionConfig) handleFunc(cmd *cobra.Command) (string, error) { } func (fc *FunctionConfig) makeHttpCall(jsonData []byte, cmd *cobra.Command) (map[string]interface{}, error) { - url := fc.replaceEnvVariables(fc.Url) - req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) + req, err := http.NewRequest("POST", fc.Url, bytes.NewBuffer(jsonData)) if err != nil { return nil, util.HandleError(cmd, err, util.INIT_HTTP_POST_REQUEST_FAILED) } for _, header := range fc.Header { - header = fc.replaceEnvVariables(header) - headerParts := strings.SplitN(header, ":", 2) if len(headerParts) == 2 { req.Header.Set(strings.TrimSpace(headerParts[0]), strings.TrimSpace(headerParts[1])) @@ -133,26 +171,11 @@ func (fc *FunctionConfig) makeHttpCall(jsonData []byte, cmd *cobra.Command) (map return responseData, nil } -func (fc *FunctionConfig) getJSONData(cmd *cobra.Command) ([]byte, error) { +func (fc *FunctionConfig) getJSONData(cmd *cobra.Command, args []string) ([]byte, error) { jsonData, err := json.Marshal(fc.Data) if err != nil { return nil, util.HandleError(cmd, err, util.MARSHAL_DATA_FAILED) } - jsonData, err = util.ReplaceStdIn(jsonData) - if err != nil { - return nil, util.HandleError(cmd, err, util.REPLACE_STDIN_FAILED) - } - return jsonData, nil } - -func (fc *FunctionConfig) replaceEnvVariables(value string) string { - for _, envVar := range fc.Env { - envValue := os.Getenv(envVar) - placeholder := fmt.Sprintf("${%s}", envVar) - value = strings.Replace(value, placeholder, envValue, -1) - } - - return value -} diff --git a/util/errors.go b/util/errors.go index 8f70444..6e48d58 100644 --- a/util/errors.go +++ b/util/errors.go @@ -19,3 +19,4 @@ var REPLACE_STDIN_FAILED = errors.New("Failed to replace stdin") var INIT_HTTP_POST_REQUEST_FAILED = errors.New("An error occurred while initializing the HTTP POST request. Possible causes could be an invalid URL or incorrect input parameters.") var SEND_HTTP_POST_REQUEST_FAILED = errors.New("An error occurred while sending the HTTP POST request. Possible causes could be network issues, server unavailability, or issues with the request payload.") var READ_RESPONSE_BODY_FAILED = errors.New("Failed to read the response body") +var REPLACE_ARGS_FAILED = errors.New("Failed to replace args") diff --git a/util/replaceStdIn.go b/util/replaceStdIn.go index 0fa731e..3d3ca79 100644 --- a/util/replaceStdIn.go +++ b/util/replaceStdIn.go @@ -45,6 +45,20 @@ func ReplaceStdIn(input []byte) ([]byte, error) { return input, nil } +func ReplaceArgs(input []byte, args []string) []byte { + if len(args) <= 1 { + return input + } + + inputStr := string(input) + for i, arg := range args[1:] { + arg = removeControlChars(arg) + inputStr = strings.Replace(inputStr, fmt.Sprintf("${ARG%d}", i+1), arg, -1) + } + + return []byte(inputStr) +} + func ParseJSONResponse(jsonData []byte) (map[string]interface{}, error) { var data map[string]interface{} err := json.Unmarshal(jsonData, &data)