diff --git a/internal/cli/bulk_transfers.go b/internal/cli/bulk_transfers.go index 2c55fd5..25b8d5f 100644 --- a/internal/cli/bulk_transfers.go +++ b/internal/cli/bulk_transfers.go @@ -95,7 +95,7 @@ func newBulkTransfersGetBatchCommand(printer output.Printer, application *app.Ap Short: "Get batch by ID", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "GET", "/api/bulk-transfers/"+args[0], "") + return runRawRequest(cmd.Context(), printer, application, "GET", rawAPIPath("api", "bulk-transfers", args[0]), "") }, } } @@ -107,7 +107,7 @@ func newBulkTransfersConfirmBatchCommand(printer output.Printer, application *ap Short: "Confirm batch", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "POST", "/api/bulk-transfers/"+args[0]+"/confirm", data) + return runRawRequest(cmd.Context(), printer, application, "POST", rawAPIPath("api", "bulk-transfers", args[0], "confirm"), data) }, } cmd.Flags().StringVar(&data, "data", "", "JSON request body") @@ -121,7 +121,7 @@ func newBulkTransfersRetryBatchCommand(printer output.Printer, application *app. Short: "Retry failed items in batch", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "POST", "/api/bulk-transfers/"+args[0]+"/retry", data) + return runRawRequest(cmd.Context(), printer, application, "POST", rawAPIPath("api", "bulk-transfers", args[0], "retry"), data) }, } cmd.Flags().StringVar(&data, "data", "", "JSON request body") @@ -175,7 +175,7 @@ func newBulkTransfersSchedulesUpdateCommand(printer output.Printer, application Short: "Update schedule", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "PUT", "/api/bulk-transfers/schedules/"+args[0], data) + return runRawRequest(cmd.Context(), printer, application, "PUT", rawAPIPath("api", "bulk-transfers", "schedules", args[0]), data) }, } cmd.Flags().StringVar(&data, "data", "", "JSON request body") @@ -188,7 +188,7 @@ func newBulkTransfersSchedulesCancelCommand(printer output.Printer, application Short: "Cancel schedule", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "DELETE", "/api/bulk-transfers/schedules/"+args[0], "") + return runRawRequest(cmd.Context(), printer, application, "DELETE", rawAPIPath("api", "bulk-transfers", "schedules", args[0]), "") }, } } @@ -199,7 +199,7 @@ func newBulkTransfersSchedulesExecutionsCommand(printer output.Printer, applicat Short: "List schedule executions", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "GET", "/api/bulk-transfers/schedules/"+args[0]+"/executions", "") + return runRawRequest(cmd.Context(), printer, application, "GET", rawAPIPath("api", "bulk-transfers", "schedules", args[0], "executions"), "") }, } } @@ -220,7 +220,7 @@ func newBulkTransfersExecutionsRetryCommand(printer output.Printer, application Short: "Retry failed execution", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "POST", "/api/bulk-transfers/executions/"+args[0]+"/retry", data) + return runRawRequest(cmd.Context(), printer, application, "POST", rawAPIPath("api", "bulk-transfers", "executions", args[0], "retry"), data) }, } cmd.Flags().StringVar(&data, "data", "", "JSON request body") diff --git a/internal/cli/cards.go b/internal/cli/cards.go index a93438e..c315968 100644 --- a/internal/cli/cards.go +++ b/internal/cli/cards.go @@ -229,7 +229,7 @@ func newCardsBalanceCommand(printer output.Printer, application *app.App) *cobra Short: "Fund or withdraw balance using v2 balance endpoint", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "POST", "/api/cards/"+args[0]+"/balance", data) + return runRawRequest(cmd.Context(), printer, application, "POST", rawAPIPath("api", "cards", args[0], "balance"), data) }, } cmd.Flags().StringVar(&data, "data", "", "JSON request body") @@ -243,7 +243,7 @@ func newCardsStatusCommand(printer output.Printer, application *app.App) *cobra. Short: "Freeze or unfreeze card using v2 status endpoint", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "POST", "/api/cards/"+args[0]+"/status", data) + return runRawRequest(cmd.Context(), printer, application, "POST", rawAPIPath("api", "cards", args[0], "status"), data) }, } cmd.Flags().StringVar(&data, "data", "", "JSON request body") @@ -367,7 +367,7 @@ func newCardsTransactionsCommand(printer output.Printer, application *app.App) * Short: "List transactions for a card", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "GET", "/api/cards/"+args[0]+"/transactions", "") + return runRawRequest(cmd.Context(), printer, application, "GET", rawAPIPath("api", "cards", args[0], "transactions"), "") }, }, &cobra.Command{ @@ -375,7 +375,7 @@ func newCardsTransactionsCommand(printer output.Printer, application *app.App) * Short: "Get single card transaction", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "GET", "/api/cards/"+args[0]+"/transactions/"+args[1], "") + return runRawRequest(cmd.Context(), printer, application, "GET", rawAPIPath("api", "cards", args[0], "transactions", args[1]), "") }, }, ) diff --git a/internal/cli/raw_request.go b/internal/cli/raw_request.go index a414728..42d7fec 100644 --- a/internal/cli/raw_request.go +++ b/internal/cli/raw_request.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "fmt" + "net/url" + "strings" "github.com/bitnob/bitnob-cli/internal/app" "github.com/bitnob/bitnob-cli/internal/output" @@ -25,3 +27,11 @@ func runRawRequest(ctx context.Context, printer output.Printer, application *app _, err = printer.Stdout.Write(append(response, '\n')) return err } + +func rawAPIPath(segments ...string) string { + escaped := make([]string, 0, len(segments)) + for _, segment := range segments { + escaped = append(escaped, url.PathEscape(segment)) + } + return "/" + strings.Join(escaped, "/") +} diff --git a/internal/cli/raw_request_test.go b/internal/cli/raw_request_test.go new file mode 100644 index 0000000..99d7feb --- /dev/null +++ b/internal/cli/raw_request_test.go @@ -0,0 +1,13 @@ +package cli + +import "testing" + +func TestRawAPIPathEscapesSegments(t *testing.T) { + t.Parallel() + + got := rawAPIPath("api", "cards", "card/123?x=1#frag", "transactions", "txn 1") + want := "/api/cards/card%2F123%3Fx=1%23frag/transactions/txn%201" + if got != want { + t.Fatalf("rawAPIPath() = %q, want %q", got, want) + } +} diff --git a/internal/cli/trading.go b/internal/cli/trading.go index b9a4510..0f3d0a3 100644 --- a/internal/cli/trading.go +++ b/internal/cli/trading.go @@ -348,7 +348,7 @@ func newTradingScheduledOrdersGetCommand(printer output.Printer, application *ap Short: "Get scheduled order", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "GET", "/api/trading/scheduled-orders/"+args[0], "") + return runRawRequest(cmd.Context(), printer, application, "GET", rawAPIPath("api", "trading", "scheduled-orders", args[0]), "") }, } } @@ -360,7 +360,7 @@ func newTradingScheduledOrdersUpdateCommand(printer output.Printer, application Short: "Update scheduled order", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "PUT", "/api/trading/scheduled-orders/"+args[0], data) + return runRawRequest(cmd.Context(), printer, application, "PUT", rawAPIPath("api", "trading", "scheduled-orders", args[0]), data) }, } cmd.Flags().StringVar(&data, "data", "", "JSON request body") @@ -373,7 +373,7 @@ func newTradingScheduledOrdersCancelCommand(printer output.Printer, application Short: "Cancel scheduled order", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "DELETE", "/api/trading/scheduled-orders/"+args[0], "") + return runRawRequest(cmd.Context(), printer, application, "DELETE", rawAPIPath("api", "trading", "scheduled-orders", args[0]), "") }, } } @@ -384,7 +384,7 @@ func newTradingScheduledOrdersExecutionsCommand(printer output.Printer, applicat Short: "List scheduled-order executions", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "GET", "/api/trading/scheduled-orders/"+args[0]+"/executions", "") + return runRawRequest(cmd.Context(), printer, application, "GET", rawAPIPath("api", "trading", "scheduled-orders", args[0], "executions"), "") }, } } @@ -449,7 +449,7 @@ func newTradingTargetOrdersGetCommand(printer output.Printer, application *app.A Short: "Get target order", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "GET", "/api/trading/target-orders/"+args[0], "") + return runRawRequest(cmd.Context(), printer, application, "GET", rawAPIPath("api", "trading", "target-orders", args[0]), "") }, } } @@ -460,7 +460,7 @@ func newTradingTargetOrdersCancelCommand(printer output.Printer, application *ap Short: "Cancel target order", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRawRequest(cmd.Context(), printer, application, "DELETE", "/api/trading/target-orders/"+args[0], "") + return runRawRequest(cmd.Context(), printer, application, "DELETE", rawAPIPath("api", "trading", "target-orders", args[0]), "") }, } }