Skip to content

fix(api): serialize NoContent as null - #1387

Open
wizzomafizzo wants to merge 1 commit into
mainfrom
fix/nocontent-null-result
Open

fix(api): serialize NoContent as null#1387
wizzomafizzo wants to merge 1 commit into
mainfrom
fix/nocontent-null-result

Conversation

@wizzomafizzo

@wizzomafizzo wizzomafizzo commented Sep 2, 2026

Copy link
Copy Markdown
Member
  • Give NoContent a MarshalJSON returning null, so the 24 void JSON-RPC methods send "result": null instead of "result": {}. The receiver must stay a value receiver: handlers return NoContent{} as an any, and encoding/json only finds a pointer-receiver marshaller on an addressable value.
  • All three send paths marshal the same models.ResponseObject, so one marshaller covers plaintext WebSocket, encrypted WebSocket and HTTP POST. No server change needed.
  • Switch media.generate and media.scrape to return NoContent{} instead of a literal nil, so void success has one representation and a nilnil suppression goes away. Neither changes on the wire — both already sent null.
  • Correct the five docs/api/methods.md entries that described {} (media.control, settings.backup.delete, mappings.new, clients.delete, clients.pair.cancel) and normalise profiles.delete's phrasing. git blame puts those five after the regression landed, so they documented the drift rather than the contract. The other 19 entries already said null.
  • Document on ResponseObject why Result has no omitempty: JSON-RPC 2.0 §5 requires the key on success, so a void method sends null rather than omitting it.
  • Zaparoo Online is unaffected. stop is the only void method in the remote allowlist and it routes through encodeEmptyResult, which hard-codes an empty object regardless of what the method returned.
  • zaparoo -api <void-method> now prints null instead of {}.

BREAKING CHANGE: 24 void methods change their wire result from {} to null. For 19 of them this brings the code in line with what the docs have always published, and null is what they sent before v2.10.0. The five methods listed above are the only ones whose documented contract changes. No first-party client is affected — the app resolves the result verbatim and ignores it for void methods, and the Rust and Go clients discard it.

Closes #1369

Summary by CodeRabbit

  • Bug Fixes

    • Void JSON-RPC operations now consistently return "result": null on success instead of an empty object or missing result.
    • Updated media generation and scraping responses to use the standard empty-result format.
    • Affected operations include media control, profile and client deletion, settings backup deletion, mapping creation, and pairing cancellation.
  • Documentation

    • Updated API method descriptions and response examples to document null success results.

NoContent is the success value for every JSON-RPC method that returns
nothing. It had no MarshalJSON and ResponseObject.Result is a plain any,
so 24 methods sent "result":{} while docs/api/methods.md publishes
"result":null. The docs also contradicted themselves: five entries
described {}, written from the regressed behaviour rather than the
contract. media.generate and media.scrape expressed the same void
success as a literal nil and already sent null, so the API carried two
shapes for one concept.

Give NoContent a value-receiver MarshalJSON returning null. The receiver
must stay a value: handlers return NoContent{} as an any, and
encoding/json only finds a pointer-receiver marshaller on an addressable
value. All three send paths marshal the same ResponseObject, so this
covers plaintext WebSocket, encrypted WebSocket and HTTP POST.

Switch media.generate and media.scrape to the sentinel so void success
has one representation and a nilnil suppression goes away. Neither
changes on the wire.

Correct the five documented-{} methods and normalise profiles.delete's
phrasing. Zaparoo Online is unaffected: stop is the only void method in
the remote allowlist and encodeEmptyResult hard-codes an empty object
regardless of what the method returned.

Closes #1369
@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: a574b8f6-bc39-41f1-896e-1bb5fd6c301c

📥 Commits

Reviewing files that changed from the base of the PR and between 7788f1a and 2661522.

📒 Files selected for processing (12)
  • docs/api/methods.md
  • pkg/api/methods/media.go
  • pkg/api/methods/media_cancel_test.go
  • pkg/api/methods/media_scrape.go
  • pkg/api/methods/media_scrape_test.go
  • pkg/api/methods/methods_test.go
  • pkg/api/methods/run.go
  • pkg/api/methods/run_test.go
  • pkg/api/models/models.go
  • pkg/api/server_post_test.go
  • pkg/api/server_ws_e2e_test.go
  • pkg/testing/mocks/api_client.go

Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review.


📝 Walkthrough

Walkthrough

Void JSON-RPC responses now return NoContent{} and serialize as "result": null. Media handlers, transport tests, API documentation, and mock responses reflect this contract.

Changes

Void response contract

Layer / File(s) Summary
NoContent serialization contract
pkg/api/methods/run.go, pkg/api/models/models.go, pkg/api/methods/run_test.go
NoContent marshals as JSON null. Successful ResponseObject values retain the result key.
Handler return values
pkg/api/methods/media.go, pkg/api/methods/media_scrape.go, pkg/api/methods/*_test.go
Media generation and media scrape handlers return NoContent{} on success. Tests assert the typed result.
Wire contract alignment
pkg/api/server_post_test.go, pkg/api/server_ws_e2e_test.go, docs/api/methods.md, pkg/testing/mocks/api_client.go
HTTP and WebSocket tests, API documentation, and mock responses use null for successful void results.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: 🔵 Low · up to 26615

Void JSON-RPC responses will change from {} to null across HTTP and WebSocket transports. The change is mergeable with explicit owner awareness because external clients that require an object-shaped success result could reject the response or behave differently.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.11% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 11 files. (1 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the primary change: serializing NoContent as JSON null.
Linked Issues check ✅ Passed The PR satisfies issue #1369 by adding a value-receiver MarshalJSON implementation that serializes NoContent as null across shared JSON-RPC response paths. It updates affected handlers, documentation,…
Out of Scope Changes check ✅ Passed The changes remain within issue #1369. The implementation, handler updates, documentation, mocks, and coverage tests directly support the NoContent serialization contract.
Full details: Linked Issues check

Explanation

The PR satisfies issue #1369 by adding a value-receiver MarshalJSON implementation that serializes NoContent as null across shared JSON-RPC response paths. It updates affected handlers, documentation, mocks, and tests, establishing a consistent wire representation for void success responses.

Full details: Docstring Coverage

Explanation

Docstring coverage is 42.11% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 11 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/nocontent-null-result

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.

@codecov

codecov Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pkg/api/methods/media.go 33.33% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

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.

fix(api): NoContent serializes as {} but the docs promise null

1 participant