Skip to content
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
2 changes: 1 addition & 1 deletion cmd/api_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func runAPIKey(cfg *config.Config) (*api.APIKeyResponse, error) {
return api.NewClient(cfg.EndpointURL, cfg.APIKey).GetAPIKey()
return api.NewClient(cfg.EndpointURL, cfg.APIKey, cfg.Debug).GetAPIKey()
}

var apiKeyCmd = &cobra.Command{
Expand Down
2 changes: 1 addition & 1 deletion cmd/auth_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func runAuthLogin(apiKey, name string) (*api.APIKeyResponse, error) {
if name == "" {
return nil, errors.New("use --name to give this key a name")
}
result, err := api.NewClient(config.EndpointURL(), apiKey).GetAPIKey()
result, err := api.NewClient(config.EndpointURL(), apiKey, debugFlag).GetAPIKey()
if err != nil {
return nil, fmt.Errorf("API key verification failed: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/auth_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func runAuthStatus() (*config.Config, *api.APIKeyResponse, *config.PersistentCon
if err != nil {
return nil, nil, nil, err
}
keyResp, err := api.NewClient(cfg.EndpointURL, cfg.APIKey).GetAPIKey()
keyResp, err := api.NewClient(cfg.EndpointURL, cfg.APIKey, cfg.Debug).GetAPIKey()
if err != nil {
return nil, nil, nil, fmt.Errorf("API key verification failed: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/contact_properties.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import (
)

func runContactPropertiesList(cfg *config.Config, customOnly bool) ([]api.ContactProperty, error) {
return api.NewClient(cfg.EndpointURL, cfg.APIKey).ListContactProperties(customOnly)
return api.NewClient(cfg.EndpointURL, cfg.APIKey, cfg.Debug).ListContactProperties(customOnly)
}

func runContactPropertiesCreate(cfg *config.Config, name, propType string) error {
return api.NewClient(cfg.EndpointURL, cfg.APIKey).CreateContactProperty(name, propType)
return api.NewClient(cfg.EndpointURL, cfg.APIKey, cfg.Debug).CreateContactProperty(name, propType)
}

var contactPropertiesCmd = &cobra.Command{
Expand Down
8 changes: 4 additions & 4 deletions cmd/contacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func contactFieldParamsFromCmd(cmd *cobra.Command) (contactFieldParams, error) {
// find

func runContactsFind(cfg *config.Config, email, userID string) ([]api.Contact, error) {
return api.NewClient(cfg.EndpointURL, cfg.APIKey).FindContacts(api.FindContactParams{
return api.NewClient(cfg.EndpointURL, cfg.APIKey, cfg.Debug).FindContacts(api.FindContactParams{
Email: email,
UserID: userID,
})
Expand Down Expand Up @@ -149,7 +149,7 @@ type contactCreateResult struct {
}

func runContactsCreate(cfg *config.Config, req api.CreateContactRequest) (string, error) {
return api.NewClient(cfg.EndpointURL, cfg.APIKey).CreateContact(req)
return api.NewClient(cfg.EndpointURL, cfg.APIKey, cfg.Debug).CreateContact(req)
}

var contactsCreateCmd = &cobra.Command{
Expand Down Expand Up @@ -196,7 +196,7 @@ var contactsCreateCmd = &cobra.Command{
// update

func runContactsUpdate(cfg *config.Config, req api.UpdateContactRequest) error {
return api.NewClient(cfg.EndpointURL, cfg.APIKey).UpdateContact(req)
return api.NewClient(cfg.EndpointURL, cfg.APIKey, cfg.Debug).UpdateContact(req)
}

var contactsUpdateCmd = &cobra.Command{
Expand Down Expand Up @@ -244,7 +244,7 @@ var contactsUpdateCmd = &cobra.Command{
// delete

func runContactsDelete(cfg *config.Config, email, userID string) error {
return api.NewClient(cfg.EndpointURL, cfg.APIKey).DeleteContact(email, userID)
return api.NewClient(cfg.EndpointURL, cfg.APIKey, cfg.Debug).DeleteContact(email, userID)
}

var contactsDeleteCmd = &cobra.Command{
Expand Down
2 changes: 1 addition & 1 deletion cmd/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func parseMailingLists(pairs []string) (map[string]bool, error) {
}

func runEventsSend(cfg *config.Config, req api.SendEventRequest) error {
return api.NewClient(cfg.EndpointURL, cfg.APIKey).SendEvent(req)
return api.NewClient(cfg.EndpointURL, cfg.APIKey, cfg.Debug).SendEvent(req)
}

var eventsCmd = &cobra.Command{
Expand Down
2 changes: 1 addition & 1 deletion cmd/lists.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func runListsList(cfg *config.Config) ([]api.MailingList, error) {
return api.NewClient(cfg.EndpointURL, cfg.APIKey).ListMailingLists()
return api.NewClient(cfg.EndpointURL, cfg.APIKey, cfg.Debug).ListMailingLists()
}

var listsCmd = &cobra.Command{
Expand Down
9 changes: 8 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@ import (

var outputFormat outputFlag = "text"
var teamFlag string
var debugFlag bool

func loadConfig() (*config.Config, error) {
return config.Load(teamFlag)
cfg, err := config.Load(teamFlag)
if err != nil {
return nil, err
}
cfg.Debug = debugFlag
return cfg, nil
}

var rootCmd = &cobra.Command{
Expand Down Expand Up @@ -66,4 +72,5 @@ func init() {
// when this action is called directly.
rootCmd.PersistentFlags().VarP(&outputFormat, "output", "o", "Output format (text, json)")
rootCmd.PersistentFlags().StringVarP(&teamFlag, "team", "t", "", "Team key name to use")
rootCmd.PersistentFlags().BoolVar(&debugFlag, "debug", false, "Print API request details before sending")
}
4 changes: 2 additions & 2 deletions cmd/transactional.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func attachmentFromPath(path string) (api.Attachment, error) {
}

func runTransactionalList(cfg *config.Config, params api.PaginationParams) ([]api.TransactionalEmail, error) {
client := api.NewClient(cfg.EndpointURL, cfg.APIKey)
client := api.NewClient(cfg.EndpointURL, cfg.APIKey, cfg.Debug)
if params.Cursor != "" {
emails, _, err := client.ListTransactional(params)
return emails, err
Expand All @@ -78,7 +78,7 @@ func runTransactionalList(cfg *config.Config, params api.PaginationParams) ([]ap
}

func runTransactionalSend(cfg *config.Config, req api.SendTransactionalRequest) error {
return api.NewClient(cfg.EndpointURL, cfg.APIKey).SendTransactional(req)
return api.NewClient(cfg.EndpointURL, cfg.APIKey, cfg.Debug).SendTransactional(req)
}

var transactionalCmd = &cobra.Command{
Expand Down
2 changes: 1 addition & 1 deletion internal/api/api_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func TestGetAPIKey(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
result, err := client.GetAPIKey()

if tt.wantAPIErr != nil {
Expand Down
34 changes: 33 additions & 1 deletion internal/api/client.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package api

import (
"bytes"
"encoding/json"
"fmt"
"io"
"math/rand/v2"
"net/http"
"os"
"time"
)

Expand Down Expand Up @@ -33,13 +35,15 @@ type Client struct {
baseURL string
apiKey string
httpClient *http.Client
debug bool
}

func NewClient(baseURL, apiKey string) *Client {
func NewClient(baseURL, apiKey string, debug bool) *Client {
return &Client{
baseURL: baseURL,
apiKey: apiKey,
httpClient: &http.Client{Timeout: 5 * time.Second},
debug: debug,
}
}

Expand Down Expand Up @@ -99,6 +103,17 @@ func (c *Client) do(req *http.Request) (*http.Response, error) {

func (c *Client) newRequest(method, path string, body io.Reader) (*http.Request, error) {
url := fmt.Sprintf("%s%s", c.baseURL, path)

var bodyBytes []byte
if body != nil && c.debug {
var err error
bodyBytes, err = io.ReadAll(body)
if err != nil {
return nil, fmt.Errorf("failed to read request body: %w", err)
}
body = bytes.NewReader(bodyBytes)
}

req, err := http.NewRequest(method, url, body)
if err != nil {
return nil, err
Expand All @@ -107,5 +122,22 @@ func (c *Client) newRequest(method, path string, body io.Reader) (*http.Request,
if body != nil {
req.Header.Set("Content-Type", "application/json")
}

if c.debug {
fmt.Fprintf(os.Stderr, "[debug] %s %s\n", method, url)
fmt.Fprintf(os.Stderr, "[debug] Authorization: Bearer [REDACTED]\n")
if req.Header.Get("Content-Type") != "" {
fmt.Fprintf(os.Stderr, "[debug] Content-Type: %s\n", req.Header.Get("Content-Type"))
}
if len(bodyBytes) > 0 {
var pretty bytes.Buffer
if json.Indent(&pretty, bodyBytes, "", " ") == nil {
fmt.Fprintf(os.Stderr, "[debug] Body:\n%s\n", pretty.String())
} else {
fmt.Fprintf(os.Stderr, "[debug] Body: %s\n", bodyBytes)
}
}
}

return req, nil
}
8 changes: 4 additions & 4 deletions internal/api/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestDo_RetryResetsBody(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
req, _ := client.newRequest(http.MethodPost, "/", bytes.NewReader([]byte(`{"hello":"world"}`)))
resp, err := client.do(req)
if err != nil {
Expand All @@ -48,7 +48,7 @@ func TestDo_RetryResetsBody(t *testing.T) {
}

func TestNewRequest(t *testing.T) {
client := NewClient("https://example.com/api/v1", "test-key")
client := NewClient("https://example.com/api/v1", "test-key", false)

tests := []struct {
name string
Expand Down Expand Up @@ -84,7 +84,7 @@ func TestNewRequest(t *testing.T) {
}

func TestNewRequest_InvalidURL(t *testing.T) {
client := NewClient("://bad-url", "test-key")
client := NewClient("://bad-url", "test-key", false)
_, err := client.newRequest(http.MethodGet, "/path", nil)
if err == nil {
t.Error("expected error for invalid URL, got nil")
Expand Down Expand Up @@ -206,7 +206,7 @@ func TestDo_Retries(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
req, _ := client.newRequest(http.MethodGet, "/", nil)
resp, err := client.do(req)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions internal/api/contact_properties_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func TestListContactProperties(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
props, err := client.ListContactProperties(tt.customOnly)

if tt.wantQuery != "" && gotQuery != tt.wantQuery {
Expand Down Expand Up @@ -147,7 +147,7 @@ func TestCreateContactProperty(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
err := client.CreateContactProperty("age", "number")

if tt.wantBody != nil {
Expand Down Expand Up @@ -186,7 +186,7 @@ func TestListContactProperties_ResponseData(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
props, err := client.ListContactProperties(false)
if err != nil {
t.Fatalf("unexpected error: %v", err)
Expand Down
8 changes: 4 additions & 4 deletions internal/api/contacts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func TestCreateContact(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
id, err := client.CreateContact(tt.req)

if tt.wantBody != nil {
Expand Down Expand Up @@ -210,7 +210,7 @@ func TestDeleteContact(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
err := client.DeleteContact(tt.email, tt.userID)

if tt.wantBody != nil {
Expand Down Expand Up @@ -323,7 +323,7 @@ func TestUpdateContact(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
err := client.UpdateContact(tt.req)

if tt.wantBody != nil {
Expand Down Expand Up @@ -425,7 +425,7 @@ func TestFindContacts(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
contacts, err := client.FindContacts(tt.params)

if tt.wantQuery != "" && gotQuery != tt.wantQuery {
Expand Down
6 changes: 3 additions & 3 deletions internal/api/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestSendEvent(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
err := client.SendEvent(SendEventRequest{
Email: "test@example.com",
EventName: "signup",
Expand Down Expand Up @@ -176,7 +176,7 @@ func TestSendEvent_RequestBody(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
client.SendEvent(tt.req)

for key, want := range tt.wantPresent {
Expand Down Expand Up @@ -258,7 +258,7 @@ func TestSendEvent_IdempotencyKey(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
client.SendEvent(SendEventRequest{
Email: "a@b.com",
EventName: "click",
Expand Down
4 changes: 2 additions & 2 deletions internal/api/lists_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func TestListMailingLists(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
lists, err := client.ListMailingLists()

if tt.wantAPIErr != nil {
Expand Down Expand Up @@ -95,7 +95,7 @@ func TestListMailingLists_ResponseData(t *testing.T) {
}))
defer server.Close()

client := NewClient(server.URL, "test-key")
client := NewClient(server.URL, "test-key", false)
lists, err := client.ListMailingLists()
if err != nil {
t.Fatalf("unexpected error: %v", err)
Expand Down
Loading