Skip to content

fix: handle array response from routine create/update API#3

Open
asabirov wants to merge 4 commits intoobay:mainfrom
asabirov:fix/routine-create-response-array
Open

fix: handle array response from routine create/update API#3
asabirov wants to merge 4 commits intoobay:mainfrom
asabirov:fix/routine-create-response-array

Conversation

@asabirov
Copy link
Copy Markdown

@asabirov asabirov commented Mar 29, 2026

Summary

  • Changed RoutineResponse.Routine from single Routine to []Routine to match the Hevy API which returns an array for the routine field in POST/PUT responses
  • Updated CreateRoutine and UpdateRoutine to extract the first element from the array

Fixes #2

Test plan

  • go build ./... passes
  • go test ./... passes
  • Manual: hevycli routine create --file routine.json succeeds
  • Manual: hevycli routine update succeeds

Summary by CodeRabbit

  • Bug Fixes

    • Consistent numeric folder ID handling across folder and routine commands: input, display, filtering, and error messages now use integer IDs.
    • Routine creation/update responses and list filtering updated for more reliable routine-folder behavior.
  • Chores

    • Removed Homebrew Cask and Scoop distribution configs.
    • Updated GitHub release repository configuration.

asabirov and others added 3 commits March 29, 2026 22:01
The Hevy API returns routine folder IDs as JSON numbers, but the Go
structs declared them as strings, causing json.Unmarshal to fail with
"cannot unmarshal number into Go struct field RoutineFolder.id of type string".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Hevy API returns the routine field as an array in POST/PUT
responses, but the client expected a single object, causing unmarshal
errors when creating or updating routines.

Fixes obay#2
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fd63504d-325e-4cfa-9ccf-6b233e6b2465

📥 Commits

Reviewing files that changed from the base of the PR and between 6bb3d6c and cad7b83.

📒 Files selected for processing (4)
  • .goreleaser.yaml
  • cmd/folder/delete.go
  • cmd/folder/get.go
  • cmd/folder/update.go
💤 Files with no reviewable changes (1)
  • .goreleaser.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/folder/get.go

📝 Walkthrough

Walkthrough

This change converts folder IDs from strings to integers across CLI and API layers, updates routine create/update response handling to expect an array of routines, and removes Homebrew Cask and Scoop release targets while updating the GitHub release owner in the release config.

Changes

Cohort / File(s) Summary
Release Configuration
.goreleaser.yaml
Removed homebrew_casks and scoops release targets and related metadata/vars; updated release.github.owner from obay to asabirov.
Folder CLI commands
cmd/folder/create.go, cmd/folder/delete.go, cmd/folder/get.go, cmd/folder/list.go, cmd/folder/update.go
Converted folder ID handling from string to int: added strconv.Atoi parsing for non-interactive args, adjusted interactive selection IDs to stringified integers, and updated output/confirmation formatting to use %d.
Routine CLI commands
cmd/routine/get.go, cmd/routine/list.go
Changed display of FolderID to numeric formatting; list now parses --folder flag into an int and filters using numeric comparison.
API types
internal/api/types.go
Routine.FolderID*int; RoutineFolder.IDint; RoutineResponse.routineRoutines []Routine (JSON tag remains routine) to accept array responses.
API client
internal/api/client.go
GetRoutineFolder, UpdateRoutineFolder, DeleteRoutineFolder now accept id int and construct numeric paths with fmt.Sprintf; CreateRoutine and UpdateRoutine now decode result.Routines[] and return the first element, returning an EMPTY_RESPONSE APIError when empty.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I hopped through types, from text to number,

IDs now march in tidy integer slumber.
Responses that once made parsers frown,
Now return arrays and won't bring me down.
A little hop, a tidy fix, and back to the burrow I go!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes substantial scope creep: changes to folder ID handling across multiple files (converting from string to int in types.go, API client methods, and CLI commands) are unrelated to the stated objective of fixing array response parsing. Remove all folder ID type changes (string to int conversions) across internal/api/types.go, internal/api/client.go, and cmd/* files, keeping only the RoutineResponse.Routine array fix. Address folder ID changes in a separate PR if needed.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: handling array responses from routine create/update API instead of single objects, which directly addresses the core issue.
Linked Issues check ✅ Passed The PR fixes the primary requirement from issue #2 by changing RoutineResponse.Routine to []Routine and updating CreateRoutine/UpdateRoutine to handle array responses, directly resolving the JSON unmarshal error reported.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
cmd/folder/get.go (2)

22-24: Update command examples to reflect integer folder IDs.

The examples show UUID-style IDs (abc123-def456) but folder IDs are now integers. Consider updating for consistency.

Suggested update
 Examples:
-  hevycli folder get abc123-def456    # Get folder by ID
-  hevycli folder get abc123 -o json   # Output as JSON`,
+  hevycli folder get 123              # Get folder by ID
+  hevycli folder get 123 -o json      # Output as JSON`,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/folder/get.go` around lines 22 - 24, Update the help/examples for the
"hevycli folder get" command to use integer IDs instead of UUID-style strings:
replace examples like "abc123-def456" with an integer example (e.g., "123") and
update the JSON example accordingly ("hevycli folder get 123 -o json"); locate
and edit the examples block associated with the folder get command (the
help/example string for the "hevycli folder get" command) so the displayed usage
matches the current integer folder ID format.

74-75: Consider handling the parse error for defensive coding.

While the error is unlikely since you control the format on line 63, silently ignoring parse errors could lead to unexpected behavior (folderID defaults to 0) if the format changes in the future.

Proposed fix
-		folderID, _ = strconv.Atoi(selected.ID)
+		var parseErr error
+		folderID, parseErr = strconv.Atoi(selected.ID)
+		if parseErr != nil {
+			return fmt.Errorf("invalid folder ID selected: %s", selected.ID)
+		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/folder/get.go` around lines 74 - 75, The code silently ignores the
strconv.Atoi error when parsing selected.ID into folderID which can leave
folderID as 0; update the parse to capture the error (e.g., val, err :=
strconv.Atoi(selected.ID)) and handle it—either return the error up the call
stack, log a clear message and exit, or provide a safe fallback—so that
malformed selected.ID is detected and handled rather than silently defaulting
folderID; reference the strconv.Atoi call, the selected.ID value, and the
folderID variable when implementing the change.
cmd/folder/delete.go (1)

90-91: Consider handling the parse error for defensive coding.

Same concern as in cmd/folder/get.go - silently ignoring the parse error could cause unexpected behavior if folderID defaults to 0.

Proposed fix
-		folderID, _ = strconv.Atoi(selected.ID)
+		var parseErr error
+		folderID, parseErr = strconv.Atoi(selected.ID)
+		if parseErr != nil {
+			return fmt.Errorf("invalid folder ID selected: %s", selected.ID)
+		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/folder/delete.go` around lines 90 - 91, The code is ignoring the error
returned by strconv.Atoi when converting selected.ID to folderID; update the
strconv.Atoi call to capture the error (e.g., folderID, err :=
strconv.Atoi(selected.ID)), check err, and handle it defensively by returning or
exiting with a clear error message (or logging) so folderID won't silently be 0;
apply the same pattern used in cmd/folder/get.go for consistent error handling
around folderID and selected.ID.
cmd/folder/update.go (1)

84-84: Consider handling the conversion error defensively.

The error from strconv.Atoi is ignored. While the selected.ID originates from a formatted integer (line 73), handling the error would prevent silent failures if the data flow changes in the future.

🛡️ Proposed fix for defensive error handling
-		folderID, _ = strconv.Atoi(selected.ID)
+		folderID, err = strconv.Atoi(selected.ID)
+		if err != nil {
+			return fmt.Errorf("invalid folder ID from selection: %s", selected.ID)
+		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/folder/update.go` at line 84, The conversion of selected.ID with
strconv.Atoi currently ignores the error; change the code to capture the
returned (id, err) from strconv.Atoi(selected.ID) and handle err defensively
(e.g., return the error from the surrounding function or log and exit) before
assigning folderID so the program fails loudly if selected.ID is not a valid
integer; update the folderID assignment site to use the parsed id variable and
ensure any error path provides a clear message referencing selected.ID.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.goreleaser.yaml:
- Line 67: The goreleaser "owner: asabirov" entry mismatches the module path in
go.mod ("module github.com/obay/hevycli"); update the Goreleaser owner to the
correct GitHub org/user (change owner: asabirov to owner: obay) or, if the
repository has intentionally moved, update the module path in go.mod to match
the new owner; ensure the "owner" field and the go.mod module path are
consistent so releases are published to the correct repo.

---

Nitpick comments:
In `@cmd/folder/delete.go`:
- Around line 90-91: The code is ignoring the error returned by strconv.Atoi
when converting selected.ID to folderID; update the strconv.Atoi call to capture
the error (e.g., folderID, err := strconv.Atoi(selected.ID)), check err, and
handle it defensively by returning or exiting with a clear error message (or
logging) so folderID won't silently be 0; apply the same pattern used in
cmd/folder/get.go for consistent error handling around folderID and selected.ID.

In `@cmd/folder/get.go`:
- Around line 22-24: Update the help/examples for the "hevycli folder get"
command to use integer IDs instead of UUID-style strings: replace examples like
"abc123-def456" with an integer example (e.g., "123") and update the JSON
example accordingly ("hevycli folder get 123 -o json"); locate and edit the
examples block associated with the folder get command (the help/example string
for the "hevycli folder get" command) so the displayed usage matches the current
integer folder ID format.
- Around line 74-75: The code silently ignores the strconv.Atoi error when
parsing selected.ID into folderID which can leave folderID as 0; update the
parse to capture the error (e.g., val, err := strconv.Atoi(selected.ID)) and
handle it—either return the error up the call stack, log a clear message and
exit, or provide a safe fallback—so that malformed selected.ID is detected and
handled rather than silently defaulting folderID; reference the strconv.Atoi
call, the selected.ID value, and the folderID variable when implementing the
change.

In `@cmd/folder/update.go`:
- Line 84: The conversion of selected.ID with strconv.Atoi currently ignores the
error; change the code to capture the returned (id, err) from
strconv.Atoi(selected.ID) and handle err defensively (e.g., return the error
from the surrounding function or log and exit) before assigning folderID so the
program fails loudly if selected.ID is not a valid integer; update the folderID
assignment site to use the parsed id variable and ensure any error path provides
a clear message referencing selected.ID.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 76ff2b74-c7e2-4b45-b92c-38bbb9a4511d

📥 Commits

Reviewing files that changed from the base of the PR and between 0a309a5 and 6bb3d6c.

📒 Files selected for processing (10)
  • .goreleaser.yaml
  • cmd/folder/create.go
  • cmd/folder/delete.go
  • cmd/folder/get.go
  • cmd/folder/list.go
  • cmd/folder/update.go
  • cmd/routine/get.go
  • cmd/routine/list.go
  • internal/api/client.go
  • internal/api/types.go

- Revert goreleaser owner to obay to match go.mod module path
- Update folder get examples to use integer IDs instead of UUIDs
- Handle strconv.Atoi errors in folder get/delete/update interactive mode
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

routine create fails to parse API response after accepting valid folder_id

1 participant