Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add argument support #11

Merged
merged 2 commits into from
Apr 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down Expand Up @@ -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:
Expand Down
69 changes: 46 additions & 23 deletions cmd/tpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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]))
Expand Down Expand Up @@ -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
}
1 change: 1 addition & 0 deletions util/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
14 changes: 14 additions & 0 deletions util/replaceStdIn.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down