Skip to content

fix-37-add-custom-unmarshalJSON-method#1343

Open
devarsh10 wants to merge 3 commits intoappwrite:masterfrom
devarsh10:fix/access-nested-structure
Open

fix-37-add-custom-unmarshalJSON-method#1343
devarsh10 wants to merge 3 commits intoappwrite:masterfrom
devarsh10:fix/access-nested-structure

Conversation

@devarsh10
Copy link

@devarsh10 devarsh10 commented Feb 12, 2026

What does this PR do?

I have added a custom unmarshalJSON method in the model twig file. Because earlier, the Go's default decoder used to skip the data field entirely and show nil. Hence, a custom unmarshalJSON method.

Test Plan

  1. Create a vendor directory using this command in the CONTRIBUTING.md insider sdk-generator directory
docker run --rm --interactive --tty --volume "$(pwd)":/app composer update --ignore-platform-reqs --optimize-autoloader --no-plugins --no-scripts --prefer-dist
  1. Run this docker run command, which will create an examples dir including the go directory
docker run --rm -v $(pwd):/app -w /app php:8.0-cli-alpine sh -c "apk add --no-cache curl && php example.php go"
  1. Inside examples/go/models/ verify preferences.go. You will see the UnmarshalJSON method

Related PRs and Issues

Issue it solves: #37

Have you read the Contributing Guidelines on issues?

Yes

Summary by CodeRabbit

  • New Features

    • Generated Go models now support JSON unmarshalling and retain the original input for later decoding.
  • Bug Fixes

    • Decode now returns a clearer error when attempted on an uninitialized model instance.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

No actionable comments were generated in the recent review. 🎉


📝 Walkthrough

Walkthrough

A new UnmarshalJSON method is added to the generated Go model template; it stores a copy of the input bytes into the model's internal data buffer and delegates to json.Unmarshal via an alias type, enabling JSON unmarshalling to populate buffered data for later Decode calls. Additionally, the Decode error handling message was changed to return "model must be initialized from raw JSON via New() or JSON unmarshalling" when len(model.data) <= 0.

Changes

Cohort / File(s) Summary
Go model template
templates/go/models/model.go.twig
Adds UnmarshalJSON(b []byte) error method when definition.additionalProperties is present: copies input bytes into the model's internal data field, defines an Alias type to avoid recursion, casts the receiver to the alias, and calls json.Unmarshal to populate model fields. Also updates Decode error handling to return "model must be initialized from raw JSON via New() or JSON unmarshalling" when len(model.data) <= 0.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

I nibble at bytes in a soft little heap,
I store them inside, where the secrets sleep.
A hop and a thunk, Unmarshal takes flight,
Fields wake from the buffer and tumble to light.
🐇✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix-37-add-custom-unmarshalJSON-method' clearly and specifically describes the main change: adding a custom UnmarshalJSON method to fix issue #37.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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
Contributor

@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

🤖 Fix all issues with AI agents
In `@templates/go/models/model.go.twig`:
- Around line 24-28: The custom UnmarshalJSON implementation for type {{
definition.name | caseUcfirst }} currently only copies raw bytes into p.data and
therefore prevents the standard JSON decoder from populating exported struct
fields; change UnmarshalJSON to unmarshal into an alias of the struct (use a
local type Alias {{ definition.name | caseUcfirst }}) so you can call the
default json.Unmarshal into that alias to populate all generated fields, then
store a copy of the raw bytes into p.data—this preserves normal field population
while keeping the raw payload.
🧹 Nitpick comments (1)
templates/go/models/model.go.twig (1)

19-22: Inconsistent slice handling between New and UnmarshalJSON.

New assigns the passed slice directly (caller and model share the same backing array), while UnmarshalJSON defensively copies. If the copy in UnmarshalJSON is intentional to prevent external mutation—and it should be—the same concern applies to New.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Go SDK generator’s base model template to add a custom UnmarshalJSON implementation intended to preserve the raw JSON payload for later decoding (via Decode()), addressing cases where the internal data field is otherwise left unset.

Changes:

  • Add UnmarshalJSON([]byte) to generated Go models to capture the raw JSON payload into the internal data field.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 28 to 32
// Alias avoids infinite recursion (the alias has no methods).
type Alias {{ definition.name | caseUcfirst }}
aux := (*Alias)(p)
return json.Unmarshal(b, aux)
}
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

Adding UnmarshalJSON to all generated models means every nested model instance will retain a copy of its raw JSON object. For large list responses or deeply nested structures this can significantly increase memory usage. If the raw payload is only needed for models with additionalProperties/Decode(), consider emitting UnmarshalJSON conditionally (similar to the additionalProperties guard nearby) to limit overhead.

Copilot uses AI. Check for mistakes.
Comment on lines 31 to 35
return json.Unmarshal(b, aux)
}

{%~ if definition.additionalProperties %}
// Use this method to get response in desired type
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

With this change, Decode() may now succeed on nested structs that were unmarshalled via encoding/json (because data is no longer empty), so the error message "cannot be used on nested struct" becomes misleading for other cases where data is empty (e.g., a zero-value model not unmarshalled from JSON). Consider updating the message to describe the actual precondition (model must be initialized from raw JSON via New() or JSON unmarshalling).

Copilot uses AI. Check for mistakes.
Comment on lines 24 to 32
func (p *{{ definition.name | caseUcfirst }}) UnmarshalJSON(b []byte) error {
p.data = make([]byte, len(b))
copy(p.data, b)

// Alias avoids infinite recursion (the alias has no methods).
type Alias {{ definition.name | caseUcfirst }}
aux := (*Alias)(p)
return json.Unmarshal(b, aux)
}
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

This change modifies JSON decoding behavior for generated Go models, but there doesn’t appear to be a generator integration test covering it. Adding a small Go test case in tests/languages/go/tests.go that json.Unmarshals a model containing an additionalProperties child (e.g., Preferences-like) and then calls Decode() would prevent regressions.

Suggested change
func (p *{{ definition.name | caseUcfirst }}) UnmarshalJSON(b []byte) error {
p.data = make([]byte, len(b))
copy(p.data, b)
// Alias avoids infinite recursion (the alias has no methods).
type Alias {{ definition.name | caseUcfirst }}
aux := (*Alias)(p)
return json.Unmarshal(b, aux)
}
{%~ if definition.additionalProperties %}
func (p *{{ definition.name | caseUcfirst }}) UnmarshalJSON(b []byte) error {
p.data = make([]byte, len(b))
copy(p.data, b)
// Alias avoids infinite recursion (the alias has no methods).
type Alias {{ definition.name | caseUcfirst }}
aux := (*Alias)(p)
return json.Unmarshal(b, aux)
}
{%~ endif %}

Copilot uses AI. Check for mistakes.
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.

1 participant

Comments