Skip to content
Open
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
4 changes: 4 additions & 0 deletions docs/stackit_curl.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ stackit curl URL [flags]

Get all the DNS zones for project with ID xxx via GET request to https://dns.api.stackit.cloud/v1/projects/xxx/zones, with header "Authorization: Bearer yyy", fail if server returns error (such as 403 Forbidden)
$ stackit curl https://dns.api.stackit.cloud/v1/projects/xxx/zones -X POST -H "Authorization: Bearer yyy" --fail

Get all the DNS zones via GET with detailed information about the request and the response
$ stackit curl https://dns.api.stackit.cloud/v1/projects/xxx/zones --verbose
```

### Options
Expand All @@ -36,6 +39,7 @@ stackit curl URL [flags]
--include If set, response headers are added to the output
--output string Writes output to provided file instead of printing to console
-X, --request string HTTP method, defaults to GET
-v, --verbose Prints the full HTTP request and response for debugging
```

### Options inherited from parent commands
Expand Down
19 changes: 19 additions & 0 deletions internal/cmd/curl/curl.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const (
includeResponseHeadersFlag = "include"
failOnHTTPErrorFlag = "fail"
outputFileFlag = "output"
verboseFlag = "verbose"
)

const (
Expand All @@ -45,6 +46,7 @@ type inputModel struct {
IncludeResponseHeaders bool
FailOnHTTPError bool
OutputFile *string
Verbose bool
}

func NewCmd(params *types.CmdParams) *cobra.Command {
Expand All @@ -69,6 +71,10 @@ func NewCmd(params *types.CmdParams) *cobra.Command {
`Get all the DNS zones for project with ID xxx via GET request to https://dns.api.stackit.cloud/v1/projects/xxx/zones, with header "Authorization: Bearer yyy", fail if server returns error (such as 403 Forbidden)`,
`$ stackit curl https://dns.api.stackit.cloud/v1/projects/xxx/zones -X POST -H "Authorization: Bearer yyy" --fail`,
),
examples.NewExample(
"Get all the DNS zones via GET with detailed information about the request and the response",
"$ stackit curl https://dns.api.stackit.cloud/v1/projects/xxx/zones --verbose",
),
),
Args: args.SingleArg(urlArg, utils.ValidateURLDomain),
RunE: func(cmd *cobra.Command, args []string) (err error) {
Expand All @@ -87,13 +93,24 @@ func NewCmd(params *types.CmdParams) *cobra.Command {
return err
}

if model.Verbose {
requestDump, _ := httputil.DumpRequest(req, true)
params.Printer.Outputln(fmt.Sprintf("--- REQUEST ---\n%s", string(requestDump)))
}

client := http.Client{
Timeout: 30 * time.Second,
}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("do request: %w", err)
}

if model.Verbose {
responseDump, _ := httputil.DumpResponse(resp, false)
params.Printer.Outputln(fmt.Sprintf("--- RESPONSE ---\n%s", string(responseDump)))
}

defer func() {
closeErr := resp.Body.Close()
if closeErr != nil {
Expand Down Expand Up @@ -136,6 +153,7 @@ func configureFlags(cmd *cobra.Command) {
cmd.Flags().Bool(includeResponseHeadersFlag, false, "If set, response headers are added to the output")
cmd.Flags().Bool(failOnHTTPErrorFlag, false, "If set, exits with error 22 if response code is 4XX or 5XX")
cmd.Flags().String(outputFileFlag, "", "Writes output to provided file instead of printing to console")
cmd.Flags().BoolP(verboseFlag, "v", false, "Prints the full HTTP request and response for debugging")
}

func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inputModel, error) {
Expand All @@ -153,6 +171,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu
IncludeResponseHeaders: flags.FlagToBoolValue(p, cmd, includeResponseHeadersFlag),
FailOnHTTPError: flags.FlagToBoolValue(p, cmd, failOnHTTPErrorFlag),
OutputFile: flags.FlagToStringPointer(p, cmd, outputFileFlag),
Verbose: flags.FlagToBoolValue(p, cmd, verboseFlag),
}

p.DebugInputModel(model)
Expand Down
13 changes: 13 additions & 0 deletions internal/cmd/curl/curl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st
includeResponseHeadersFlag: "true",
failOnHTTPErrorFlag: "true",
outputFileFlag: "./output.txt",
verboseFlag: "false",
}
for _, mod := range mods {
mod(flagValues)
Expand All @@ -58,6 +59,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
IncludeResponseHeaders: true,
FailOnHTTPError: true,
OutputFile: utils.Ptr("./output.txt"),
Verbose: false,
}
for _, mod := range mods {
mod(model)
Expand Down Expand Up @@ -213,6 +215,17 @@ func TestParseInput(t *testing.T) {
)
}),
},
{
description: "verbose flag",
argValues: fixtureArgValues(),
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
flagValues[verboseFlag] = "true"
}),
isValid: true,
expectedModel: fixtureInputModel(func(model *inputModel) {
model.Verbose = true
}),
},
}

for _, tt := range tests {
Expand Down
Loading