You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If a JSON value is not appropriate for a given target type, or if a JSON number overflows the target type, Unmarshal skips that field and completes the unmarshaling as best it can. If no more serious errors are encountered, Unmarshal returns an UnmarshalTypeError describing the earliest such error.
However, GetWithETag treats all errors from json.Unmarshall as catastrophic failures: it returns an empty etag despite the value v being populated by json.Unmarshall().
The client doesn't receive a valid etag from either method: every subsequent call to GetIfChanged will retrieve the full reference data (expensive)
GetIfChanged will never return changed=true: if the client code uses changed to detect changes then it will never update (client will not act on the changes that it has been able to process)
I would expect the methods above to return any etag in the response - even when the client has subsequently generated an error while trying to process the body of that response. This ensures that the client doesn't repeatedly download and process a message that it can't.
This seems to be caused by the HTTP client - which fails to return the response if it encounters an unmarshal error. So, neither of the two methods above are able to retrieve the etag from the response that hasn't been returned.
returnnil, fmt.Errorf("error while parsing response: %v", err)
Workaround
There is a workaround - the client can use json.RawMessage to defer parsing the response. This ensures that GetIfChanged and GetWithETag will not encounter an unmarshalling error and will therefore always return the etag.
var v json.RawMessage
etag, err := ref.GetWithETag(context.Background(), &v)
if err != nil {
// This can only be an error in the request - for example, a connection failure. Handle appropriately.
}
data := make(<your data struct>)
err = json.Unmarshal(v, &data)
if err != nil {
// This could be one of three errors: InvalidUnmarshalError , SyntaxError, or UnmarshalTypeError.
// InvalidUnmarshalError indicates that data is nil; SyntaxError indicates that Firebase has returned non-json data
// UnmarshalTypeError indicates at least one schema error in the data - but data object will be populated as best it can be
// Handle appropriately.
}
The text was updated successfully, but these errors were encountered:
Describe your environment
Describe the problem
json.Unmarshal() is robust to schema issues - it will populate as much of the value as possible.
https://pkg.go.dev/encoding/json#Unmarshal
However, GetWithETag treats all errors from json.Unmarshall as catastrophic failures: it returns an empty etag despite the value v being populated by json.Unmarshall().
firebase-admin-go/db/ref.go
Line 93 in 74c9bd5
GetIfChanged is similar. It returns an empty etag, and also fails to declare if the data has changed.
firebase-admin-go/db/ref.go
Line 130 in 74c9bd5
The consequences are:
I would expect the methods above to return any etag in the response - even when the client has subsequently generated an error while trying to process the body of that response. This ensures that the client doesn't repeatedly download and process a message that it can't.
This seems to be caused by the HTTP client - which fails to return the response if it encounters an unmarshal error. So, neither of the two methods above are able to retrieve the etag from the response that hasn't been returned.
firebase-admin-go/internal/http_client.go
Line 170 in 74c9bd5
Workaround
There is a workaround - the client can use json.RawMessage to defer parsing the response. This ensures that GetIfChanged and GetWithETag will not encounter an unmarshalling error and will therefore always return the etag.
The text was updated successfully, but these errors were encountered: