github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/pkg/jsonapi/data.go (about) 1 package jsonapi 2 3 import ( 4 "encoding/json" 5 6 "github.com/cozy/cozy-stack/pkg/couchdb" 7 ) 8 9 // Object is an interface to serialize something to a JSON-API Object 10 type Object interface { 11 couchdb.Doc 12 Links() *LinksList 13 Relationships() RelationshipMap 14 Included() []Object 15 } 16 17 // Meta is a container for the couchdb revision and the total number of items, 18 // in JSON-API land 19 type Meta struct { 20 Rev string `json:"rev,omitempty"` 21 Warning string `json:"warning,omitempty"` 22 Count *int `json:"count,omitempty"` 23 ExecutionStats *couchdb.ExecutionStats `json:"execution_stats,omitempty"` 24 } 25 26 // LinksList is the common links used in JSON-API for the top-level or a 27 // resource object 28 // See http://jsonapi.org/format/#document-links 29 type LinksList struct { 30 Self string `json:"self,omitempty"` 31 Related string `json:"related,omitempty"` 32 Prev string `json:"prev,omitempty"` 33 Next string `json:"next,omitempty"` 34 Icon string `json:"icon,omitempty"` 35 Perms string `json:"permissions,omitempty"` 36 Webhook string `json:"webhook,omitempty"` 37 // Thumbnails 38 Tiny string `json:"tiny,omitempty"` 39 Small string `json:"small,omitempty"` 40 Medium string `json:"medium,omitempty"` 41 Large string `json:"large,omitempty"` 42 // Preview for PDF 43 Preview string `json:"preview,omitempty"` 44 } 45 46 // Relationship is a resource linkage, as described in JSON-API 47 // See http://jsonapi.org/format/#document-resource-object-relationships 48 // 49 // Data can be a single ResourceIdentifier for to-one relationships, 50 // or an array of them for to-many relationships. 51 type Relationship struct { 52 Links *LinksList `json:"links,omitempty"` 53 Meta *Meta `json:"meta,omitempty"` 54 Data interface{} `json:"data"` 55 } 56 57 // ResourceIdentifier returns the resource identifier of the relationship. 58 func (r *Relationship) ResourceIdentifier() (*couchdb.DocReference, bool) { 59 if m, ok := r.Data.(map[string]interface{}); ok { 60 idd, _ := m["id"].(string) 61 typ, _ := m["type"].(string) 62 return &couchdb.DocReference{ID: idd, Type: typ}, true 63 } 64 return nil, false 65 } 66 67 // RelationshipMap is a map of relationships 68 // See http://jsonapi.org/format/#document-resource-object-relationships 69 type RelationshipMap map[string]Relationship 70 71 // ObjectMarshalling is a JSON-API object 72 // See http://jsonapi.org/format/#document-resource-objects 73 type ObjectMarshalling struct { 74 Type string `json:"type"` 75 ID string `json:"id"` 76 Attributes *json.RawMessage `json:"attributes"` 77 Meta Meta `json:"meta"` 78 Links *LinksList `json:"links,omitempty"` 79 Relationships RelationshipMap `json:"relationships,omitempty"` 80 } 81 82 // GetRelationship returns the relationship with the given name from 83 // the relationships map. 84 func (o *ObjectMarshalling) GetRelationship(name string) (*Relationship, bool) { 85 rel, ok := o.Relationships[name] 86 if !ok { 87 return nil, false 88 } 89 return &rel, true 90 } 91 92 // MarshalObject serializes an Object to JSON. 93 // It returns a json.RawMessage that can be used a in Document. 94 func MarshalObject(o Object) (json.RawMessage, error) { 95 id := o.ID() 96 rev := o.Rev() 97 links := o.Links() 98 rels := o.Relationships() 99 100 o.SetID("") 101 o.SetRev("") 102 defer func() { 103 o.SetID(id) 104 o.SetRev(rev) 105 }() 106 107 b, err := json.Marshal(o) 108 if err != nil { 109 return nil, err 110 } 111 112 data := ObjectMarshalling{ 113 Type: o.DocType(), 114 ID: id, 115 Attributes: (*json.RawMessage)(&b), 116 Meta: Meta{Rev: rev}, 117 Links: links, 118 Relationships: rels, 119 } 120 return json.Marshal(data) 121 }