@@ -23,53 +23,103 @@ var (
2323 // be a slice of *Structs; MarshalMany will return this error when its
2424 // interface{} argument is invalid.
2525 ErrExpectedSlice = errors .New ("models should be a slice of struct pointers" )
26+ // ErrUnexpectedType is returned when marshalling an interface; the interface
27+ // had to be a pointer or a slice; otherwise this error is returned.
28+ ErrUnexpectedType = errors .New ("models should be a struct pointer or slice of struct pointers" )
2629)
2730
28- // MarshalOnePayload writes a jsonapi response with one, with related records
29- // sideloaded, into "included" array. This method encodes a response for a
30- // single record only. Hence, data will be a single record rather than an array
31- // of records. If you want to serialize many records, see, MarshalManyPayload.
31+ // MarshalPayload writes a jsonapi response for one or many records. The
32+ // related records are sideloaded into the "included" array. If this method is
33+ // given a struct pointer as an argument it will serialize in the form
34+ // "data": {...}. If this method is given a slice of pointers, this method will
35+ // serialize in the form "data": [...]
3236//
33- // See UnmarshalPayload for usage example.
37+ // One Example: you could pass it, w, your http.ResponseWriter, and, models, a
38+ // ptr to a Blog to be written to the response body:
3439//
35- // model interface{} should be a pointer to a struct.
36- func MarshalOnePayload (w io.Writer , model interface {}) error {
37- payload , err := MarshalOne (model )
40+ // func ShowBlog(w http.ResponseWriter, r *http.Request) {
41+ // blog := &Blog{}
42+ //
43+ // w.Header().Set("Content-Type", jsonapi.MediaType)
44+ // w.WriteHeader(http.StatusOK)
45+ //
46+ // if err := jsonapi.MarshalPayload(w, blog); err != nil {
47+ // http.Error(w, err.Error(), http.StatusInternalServerError)
48+ // }
49+ // }
50+ //
51+ // Many Example: you could pass it, w, your http.ResponseWriter, and, models, a
52+ // slice of Blog struct instance pointers to be written to the response body:
53+ //
54+ // func ListBlogs(w http.ResponseWriter, r *http.Request) {
55+ // blogs := []*Blog{}
56+ //
57+ // w.Header().Set("Content-Type", jsonapi.MediaType)
58+ // w.WriteHeader(http.StatusOK)
59+ //
60+ // if err := jsonapi.MarshalPayload(w, blogs); err != nil {
61+ // http.Error(w, err.Error(), http.StatusInternalServerError)
62+ // }
63+ // }
64+ //
65+ func MarshalPayload (w io.Writer , models interface {}) error {
66+ payload , err := Marshal (models )
3867 if err != nil {
3968 return err
4069 }
4170
4271 if err := json .NewEncoder (w ).Encode (payload ); err != nil {
4372 return err
4473 }
45-
4674 return nil
4775}
4876
49- // MarshalOnePayloadWithoutIncluded writes a jsonapi response with one object,
50- // without the related records sideloaded into "included" array. If you want to
51- // serialize the relations into the "included" array see MarshalOnePayload.
52- //
53- // model interface{} should be a pointer to a struct.
54- func MarshalOnePayloadWithoutIncluded (w io.Writer , model interface {}) error {
55- included := make (map [string ]* Node )
77+ // Marshal does the same as MarshalPayload except it just returns the payload
78+ // and doesn't write out results. Useful if you use your own JSON rendering
79+ // library.
80+ func Marshal (models interface {}) (Payloader , error ) {
81+ switch vals := reflect .ValueOf (models ); vals .Kind () {
82+ case reflect .Slice :
83+ m , err := convertToSliceInterface (& models )
84+ if err != nil {
85+ return nil , err
86+ }
87+ return marshalMany (m )
88+ case reflect .Ptr :
89+ // Check that the pointer was to a struct
90+ if reflect .Indirect (vals ).Kind () != reflect .Struct {
91+ return nil , ErrUnexpectedType
92+ }
93+ return marshalOne (models )
94+ default :
95+ return nil , ErrUnexpectedType
96+ }
97+ }
5698
57- rootNode , err := visitModelNode (model , & included , true )
99+ // MarshalPayloadWithoutIncluded writes a jsonapi response with one or many
100+ // records, without the related records sideloaded into "included" array.
101+ // If you want to serialize the relations into the "included" array see
102+ // MarshalPayload.
103+ //
104+ // models interface{} should be either a struct pointer or a slice of struct
105+ // pointers.
106+ func MarshalPayloadWithoutIncluded (w io.Writer , model interface {}) error {
107+ payload , err := Marshal (model )
58108 if err != nil {
59109 return err
60110 }
111+ payload .clearIncluded ()
61112
62- if err := json .NewEncoder (w ).Encode (& OnePayload { Data : rootNode } ); err != nil {
113+ if err := json .NewEncoder (w ).Encode (payload ); err != nil {
63114 return err
64115 }
65-
66116 return nil
67117}
68118
69- // MarshalOne does the same as MarshalOnePayload except it just returns the
119+ // marshalOne does the same as MarshalOnePayload except it just returns the
70120// payload and doesn't write out results. Useful is you use your JSON rendering
71121// library.
72- func MarshalOne (model interface {}) (* OnePayload , error ) {
122+ func marshalOne (model interface {}) (* OnePayload , error ) {
73123 included := make (map [string ]* Node )
74124
75125 rootNode , err := visitModelNode (model , & included , true )
@@ -83,78 +133,10 @@ func MarshalOne(model interface{}) (*OnePayload, error) {
83133 return payload , nil
84134}
85135
86- // MarshalManyPayloadWithoutIncluded writes a jsonapi response with many records,
87- // without the related records sideloaded into "included" array. If you want to
88- // serialize the relations into the "included" array see MarshalManyPayload.
89- //
90- // models interface{} should be a slice of struct pointers.
91- func MarshalManyPayloadWithoutIncluded (w io.Writer , models interface {}) error {
92- m , err := convertToSliceInterface (& models )
93- if err != nil {
94- return err
95- }
96- payload , err := MarshalMany (m )
97- if err != nil {
98- return err
99- }
100-
101- // Empty the included
102- payload .Included = []* Node {}
103-
104- if err := json .NewEncoder (w ).Encode (payload ); err != nil {
105- return err
106- }
107-
108- return nil
109- }
110-
111- // MarshalManyPayload writes a jsonapi response with many records, with related
112- // records sideloaded, into "included" array. This method encodes a response for
113- // a slice of records, hence data will be an array of records rather than a
114- // single record. To serialize a single record, see MarshalOnePayload
115- //
116- // For example you could pass it, w, your http.ResponseWriter, and, models, a
117- // slice of Blog struct instance pointers as interface{}'s to write to the
118- // response,
119- //
120- // func ListBlogs(w http.ResponseWriter, r *http.Request) {
121- // // ... fetch your blogs and filter, offset, limit, etc ...
122- //
123- // blogs := testBlogsForList()
124- //
125- // w.Header().Set("Content-Type", jsonapi.MediaType)
126- // w.WriteHeader(http.StatusOK)
127- //
128- // if err := jsonapi.MarshalManyPayload(w, blogs); err != nil {
129- // http.Error(w, err.Error(), http.StatusInternalServerError)
130- // }
131- // }
132- //
133- //
134- // Visit https://github.com/google/jsonapi#list for more info.
135- //
136- // models interface{} should be a slice of struct pointers.
137- func MarshalManyPayload (w io.Writer , models interface {}) error {
138- m , err := convertToSliceInterface (& models )
139- if err != nil {
140- return err
141- }
142- payload , err := MarshalMany (m )
143- if err != nil {
144- return err
145- }
146-
147- if err := json .NewEncoder (w ).Encode (payload ); err != nil {
148- return err
149- }
150-
151- return nil
152- }
153-
154- // MarshalMany does the same as MarshalManyPayload except it just returns the
136+ // marshalMany does the same as MarshalManyPayload except it just returns the
155137// payload and doesn't write out results. Useful is you use your JSON rendering
156138// library.
157- func MarshalMany (models []interface {}) (* ManyPayload , error ) {
139+ func marshalMany (models []interface {}) (* ManyPayload , error ) {
158140 payload := & ManyPayload {
159141 Data : []* Node {},
160142 }
@@ -173,16 +155,18 @@ func MarshalMany(models []interface{}) (*ManyPayload, error) {
173155}
174156
175157// MarshalOnePayloadEmbedded - This method not meant to for use in
176- // implementation code, although feel free. The purpose of this method is for
177- // use in tests. In most cases, your request payloads for create will be
178- // embedded rather than sideloaded for related records. This method will
179- // serialize a single struct pointer into an embedded json response. In other
180- // words, there will be no, "included", array in the json all relationships will
158+ // implementation code, although feel free. The purpose of this
159+ // method is for use in tests. In most cases, your request
160+ // payloads for create will be embedded rather than sideloaded for
161+ // related records. This method will serialize a single struct
162+ // pointer into an embedded json response. In other words, there
163+ // will be no, "included", array in the json all relationships will
181164// be serailized inline in the data.
182165//
183- // However, in tests, you may want to construct payloads to post to create
184- // methods that are embedded to most closely resemble the payloads that will be
185- // produced by the client. This is what this method is intended for.
166+ // However, in tests, you may want to construct payloads to post
167+ // to create methods that are embedded to most closely resemble
168+ // the payloads that will be produced by the client. This is what
169+ // this method is intended for.
186170//
187171// model interface{} should be a pointer to a struct.
188172func MarshalOnePayloadEmbedded (w io.Writer , model interface {}) error {
0 commit comments