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
{{ message }}
This repository was archived by the owner on Sep 4, 2025. It is now read-only.
Repository navigation
This repository was archived by the owner on Sep 4, 2025. It is now read-only.
Simplification of Unmarshal API & Access to Meta and Links #95
With the recent simplification of the Marshal API (cf83b97) I think it might be a good time to consider something similar for the Unmarshal case.
While doing so, it would be even better to provide a solution for accessing the Meta and Links of the JSON API document (relevant issues #82, #68 and #64).
Right now there are two core functions that handle Unmarshaling:
As long as the model is a pointer to a struct or a pointer to a slice, these can be simplified to one function with the same exact signature as UnmarshalPayload(in io.Reader, model interface{}) error. I have already done a proof of concept (nstratos/go-kitsu@8b8706c) for a package I am writing and it seems to be working fine.
The name could be kept the same for compatibility while emphasizing in the docs the new functionality of providing a pointer to slice to fill with data (instead of using UnmarshalManyPayload) or it could be made to new a function that covers both cases. For this discussion I am going to name this new function UnmarshalAll but it could be anything.
A separate but related issue (because of the function signature) is giving access to Meta and Links. The simplest way would be to return something extra besides the error. Perhaps something like this:
typeExtrasstruct {
Links*LinksMeta*Meta
}
// Expecting v to be pointer to struct or pointer to slice.funcUnmarshalAll(r io.Reader, vinterface{}) (Extras, error)
Thus with this function, the Unmarshal API gets simplified and access to Meta and LInks is provided as well.
This extra workload is why I only bit off simplifying the Marshal API initially.
With that being said I have put a lot of thought into this. I had considered doing something similar to what you have suggested, however I could not work out how it would work out in a situation where like links are on the top level data collection (self/next/last) and also on each memeber of said collection (self). Example:
{"links": {"self": "http://example.com/articles","next": "http://example.com/articles?page[offset]=2","last": "http://example.com/articles?page[offset]=10"},"data": [{"type": "articles","id": "1","attributes": {"title": "JSON API paints my bikeshed!"},"links": {"self": "http://example.com/articles/1"}}]}
I think a better solution is to have the generic Unmarshal look like:
funcUnmarshal(r io.Reader, tinterface{}) error
The t passed in would optionally implement a defined interface for handling Meta/Links etc.
In this way the same interface can be used for types representing a collection as well as with types that are members of the collection.
Both Team and Teams in the example above would implement an optional interface for handling Meta. Then given the following JSON API payload to Unmarshal:
I have the exact case that @aren55555 noted: a response with the data portion being a list of individual objects then a links object with those pagination fields.
Is there an ugly way to workaround this in lieu of an elegant solution? In my own code I've done this:
type PaginationLinks struct {
Self string `json:"self,omitempty"`
First string `json:"first,omitempty"`
Last string `json:"last,omitempty"`
Next string `json:"next,omitempty"`
Prev string `json:"prev,omitempty"`
}
type Page struct {
Links *PaginationLinks `json:"links,omitempty"`
Data interface{} `json:"data,omitempty"`
}
func (p PaginationLinks) NextPage() string {
return p.Next
}
Hi there 👋 Am I understanding this discussion correctly, that currently there is no way to access meta when using UnmarshalPayload or UnmarshalManyPayload? #82 implies that this is still the case.
@nstratos@aren55555 any information on the status of this and the project itself? Would love to be able to easily access links from responses as a client. For example being able to access the redirect field:
Obviously the above would only solve being able to access meta/links at a resource level and not the top level. I suppose for that the unmarshal function would need to return something for those.
Edit: I've had a go at the above for meta attributes, seems to work OK, see here. I can submit a PR if needs be!
Activity
aren55555 commentedon Jul 6, 2017
This extra workload is why I only bit off simplifying the Marshal API initially.
With that being said I have put a lot of thought into this. I had considered doing something similar to what you have suggested, however I could not work out how it would work out in a situation where like links are on the top level data collection (
self/next/last) and also on each memeber of said collection (self). Example:I think a better solution is to have the generic
Unmarshallook like:The
tpassed in would optionally implement a defined interface for handlingMeta/Linksetc.In this way the same interface can be used for types representing a collection as well as with types that are members of the collection.
Both
TeamandTeamsin the example above would implement an optional interface for handlingMeta. Then given the following JSON API payload to Unmarshal:Teamsimplementation of the interface would have to handle the part:and the
Teamimplementation of the interface would have to handle the part:or
I haven't yet stared on this - it's just the pattern that I have left to brew in the back of my head.
svperfecta commentedon Aug 31, 2017
See also #110 :)
SelfDrivingCarp commentedon May 30, 2018
I have the exact case that @aren55555 noted: a response with the
dataportion being a list of individual objects then alinksobject with those pagination fields.Is there an ugly way to workaround this in lieu of an elegant solution? In my own code I've done this:
tisba commentedon Aug 7, 2018
Hi there 👋 Am I understanding this discussion correctly, that currently there is no way to access
metawhen usingUnmarshalPayloadorUnmarshalManyPayload? #82 implies that this is still the case.AndreasBackx commentedon Oct 10, 2018
@nstratos @aren55555 any information on the status of this and the project itself? Would love to be able to easily access links from responses as a client. For example being able to access the
redirectfield:Edit: this might be incorrect according to the links spec.
adamlc commentedon Jan 30, 2019
This would also be really useful for me. What about if we had the meta embedded in the struct (same with links)? Using the teams example above:
{ "data": [{ "type": "team", "id": "1", "attributes": { "name": "Toronto Maple Leafs" }, "meta": { "details": 19 } }, { "type": "team", "id": "3", "attributes": { "name": "Toronto Raptors" }, "meta": { "details": 15 } }], "meta": { "details": "updated" } }Obviously the above would only solve being able to access meta/links at a resource level and not the top level. I suppose for that the unmarshal function would need to return something for those.
Edit: I've had a go at the above for meta attributes, seems to work OK, see here. I can submit a PR if needs be!
gadelkareem commentedon May 9, 2020
Any updates on this?