Documentation
¶
Overview ¶
Package jsonapi implements encoding and decoding of JSON:API as defined in https://jsonapi.org/format/.
Index ¶
- Variables
- func Marshal(v any, opts ...MarshalOption) (b []byte, err error)
- func Status(s int) *int
- func Unmarshal(data []byte, v any, opts ...UnmarshalOption) (err error)
- type Error
- type ErrorLink
- type ErrorSource
- type Link
- type LinkObject
- type Linkable
- type LinkableRelation
- type MarshalIdentifier
- type MarshalOption
- func MarshalClientMode() MarshalOption
- func MarshalFields(query url.Values) MarshalOption
- func MarshalInclude(v ...any) MarshalOption
- func MarshalJSONAPI(meta any) MarshalOption
- func MarshalLinks(l *Link) MarshalOption
- func MarshalMeta(meta any) MarshalOption
- func MarshalSetNameValidation(mode MemberNameValidationMode) MarshalOption
- func MarshallCheckUniqueness() MarshalOption
- type MarshalType
- type Marshaler
- type MemberNameValidationError
- type MemberNameValidationMode
- type PartialLinkageError
- type TagError
- type TypeError
- type UnmarshalIdentifier
- type UnmarshalOption
- type UnmarshalType
- type Unmarshaler
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrMarshalInvalidPrimaryField indicates that the id (primary) fields was invalid. ErrMarshalInvalidPrimaryField = errors.New("primary/id field must be a string or implement fmt.Stringer or in a struct which implements MarshalIdentifier") // ErrUnmarshalInvalidPrimaryField indicates that the id (primary) fields was invalid. ErrUnmarshalInvalidPrimaryField = errors.New("primary/id field must be a string or in a struct which implements UnmarshalIdentifer") // ErrUnmarshalDuplicatePrimaryField indicates that the id (primary) field is duplicated in a struct. ErrUnmarshalDuplicatePrimaryField = errors.New("there must be only one `jsonapi:\"primary\"` field to Unmarshal") // ErrMissingPrimaryField indicates that the id (primary) field is not identified. ErrMissingPrimaryField = errors.New("primary/id field must labeled with `jsonapi:\"primary,{type}\"`") // ErrEmptyPrimaryField indicates that the id (primary) field is identified but empty. ErrEmptyPrimaryField = errors.New("the `jsonapi:\"primary\"` field value must not be empty") // ErrMissingLinkFields indicates that a LinkObject is not valid. ErrMissingLinkFields = errors.New("at least one of Links.Self or Links.Related must be set to a nonempty string or *LinkObject") // ErrEmptyDataObject indicates that a primary or relationship data member is incorrectly represented by an empty JSON object {} ErrEmptyDataObject = errors.New("resource \"data\" members may not be represented by an empty object {}") // ErrDocumentMissingRequiredMembers indicates that a document does not have at least one required top-level member ErrDocumentMissingRequiredMembers = errors.New("document is missing required top-level members; must have one of: \"data\", \"meta\", \"errors\"") // ErrRelationshipMissingRequiredMembers indicates that a relationship does not have at least one required member ErrRelationshipMissingRequiredMembers = errors.New("relationship is missing required top-level members; must have one of: \"data\", \"meta\", \"links\"") // ErrNonuniqueResource indicates that multiple resource objects across the primary data and included sections share // the same type & id, or multiple resource linkages with the same type & id exist in a relationship section ErrNonuniqueResource = errors.New("\"type\" and \"id\" must be unique across resources") // ErrErrorUnmarshalingNotImplemented indicates that an attempt was made to unmarshal an error document ErrErrorUnmarshalingNotImplemented = errors.New("error unmarshaling is not implemented") )
Functions ¶
func Marshal ¶
func Marshal(v any, opts ...MarshalOption) (b []byte, err error)
Marshal returns the json:api encoding of v. If v is type *Error or []*Error only the errors will be marshaled.
Example ¶
package main
import (
"fmt"
"github.com/DataDog/jsonapi"
)
func main() {
type Article struct {
ID string `jsonapi:"primary,articles"`
Title string `jsonapi:"attribute" json:"title"`
}
a := Article{ID: "1", Title: "Hello World"}
b, err := jsonapi.Marshal(&a)
if err != nil {
panic(err)
}
fmt.Printf("%s", string(b))
}
Output: {"data":{"id":"1","type":"articles","attributes":{"title":"Hello World"}}}
Example (Meta) ¶
package main
import (
"fmt"
"github.com/DataDog/jsonapi"
)
func main() {
type ArticleMeta struct {
Views int `json:"views"`
}
type Article struct {
ID string `jsonapi:"primary,articles"`
Title string `jsonapi:"attribute" json:"title"`
Meta *ArticleMeta `jsonapi:"meta"`
}
a := Article{ID: "1", Title: "Hello World", Meta: &ArticleMeta{Views: 10}}
m := map[string]any{"foo": "bar"}
b, err := jsonapi.Marshal(&a, jsonapi.MarshalMeta(m))
if err != nil {
panic(err)
}
fmt.Printf("%s", string(b))
}
Output: {"data":{"id":"1","type":"articles","attributes":{"title":"Hello World"},"meta":{"views":10}},"meta":{"foo":"bar"}}
Example (Relationships) ¶
package main
import (
"fmt"
"github.com/DataDog/jsonapi"
)
type Author struct {
ID string `jsonapi:"primary,author"`
Name string `jsonapi:"attribute" json:"name"`
}
type Comment struct {
ID string `jsonapi:"primary,comments"`
Body string `jsonapi:"attribute" json:"comment"`
Author *Author `jsonapi:"relationship"`
}
func (c *Comment) LinkRelation(relation string) *jsonapi.Link {
return &jsonapi.Link{
Self: fmt.Sprintf("http://example.com/comments/%s/relationships/%s", c.ID, relation),
Related: fmt.Sprintf("http://example.com/comments/%s/%s", c.ID, relation),
}
}
type Article struct {
ID string `jsonapi:"primary,articles"`
Title string `jsonapi:"attribute" json:"title"`
Author *Author `jsonapi:"relationship" json:"author,omitempty"`
Comments []*Comment `jsonapi:"relationship" json:"comments,omitempty"`
}
func (a *Article) LinkRelation(relation string) *jsonapi.Link {
return &jsonapi.Link{
Self: fmt.Sprintf("http://example.com/articles/%s/relationships/%s", a.ID, relation),
Related: fmt.Sprintf("http://example.com/articles/%s/%s", a.ID, relation),
}
}
func main() {
authorA := &Author{ID: "AA", Name: "Cool Author"}
authorB := &Author{ID: "AB", Name: "Cool Commenter"}
authorC := &Author{ID: "AC", Name: "Neat Commenter"}
commentA := &Comment{ID: "CA", Body: "Very cool", Author: authorB}
commentB := &Comment{ID: "CB", Body: "Super neat", Author: authorC}
article := Article{
ID: "1",
Title: "Hello World",
Author: authorA,
Comments: []*Comment{commentA, commentB},
}
b, err := jsonapi.Marshal(&article)
if err != nil {
panic(err)
}
fmt.Printf("%s", string(b))
}
Output: {"data":{"id":"1","type":"articles","attributes":{"title":"Hello World"},"relationships":{"author":{"data":{"id":"AA","type":"author"},"links":{"self":"http://example.com/articles/1/relationships/author","related":"http://example.com/articles/1/author"}},"comments":{"data":[{"id":"CA","type":"comments"},{"id":"CB","type":"comments"}],"links":{"self":"http://example.com/articles/1/relationships/comments","related":"http://example.com/articles/1/comments"}}}}}
Example (Slice) ¶
package main
import (
"fmt"
"github.com/DataDog/jsonapi"
)
func main() {
type Article struct {
ID string `jsonapi:"primary,articles"`
Title string `jsonapi:"attribute" json:"title"`
}
a := []*Article{
{ID: "1", Title: "Hello World"},
{ID: "2", Title: "Hello Again"},
}
b, err := jsonapi.Marshal(&a)
if err != nil {
panic(err)
}
fmt.Printf("%s", string(b))
}
Output: {"data":[{"id":"1","type":"articles","attributes":{"title":"Hello World"}},{"id":"2","type":"articles","attributes":{"title":"Hello Again"}}]}
func Unmarshal ¶
func Unmarshal(data []byte, v any, opts ...UnmarshalOption) (err error)
Unmarshal parses the json:api encoded data and stores the result in the value pointed to by v. If v is nil or not a pointer, Unmarshal returns an error.
Example ¶
package main
import (
"fmt"
"github.com/DataDog/jsonapi"
)
func main() {
body := `{"data":{"id":"1","type":"articles","attributes":{"title":"Hello World"}}}`
type Article struct {
ID string `jsonapi:"primary,articles"`
Title string `jsonapi:"attribute" json:"title"`
}
var a Article
err := jsonapi.Unmarshal([]byte(body), &a)
if err != nil {
panic(err)
}
fmt.Printf("%+v", &a)
}
Output: &{ID:1 Title:Hello World}
Example (Slice) ¶
package main
import (
"fmt"
"github.com/DataDog/jsonapi"
)
func main() {
body := `{"data":[{"id":"1","type":"articles","attributes":{"title":"Hello World"}},{"id":"2","type":"articles","attributes":{"title":"Hello Again"}}]}`
type Article struct {
ID string `jsonapi:"primary,articles"`
Title string `jsonapi:"attribute" json:"title"`
}
var a []*Article
err := jsonapi.Unmarshal([]byte(body), &a)
if err != nil {
panic(err)
}
fmt.Printf("%+v %+v", a[0], a[1])
}
Output: &{ID:1 Title:Hello World} &{ID:2 Title:Hello Again}
Types ¶
type Error ¶
type Error struct {
ID string `json:"id,omitempty"`
Links *ErrorLink `json:"links,omitempty"`
Status *int `json:"status,omitempty"`
Code string `json:"code,omitempty"`
Title string `json:"title,omitempty"`
Detail string `json:"detail,omitempty"`
Source *ErrorSource `json:"source,omitempty"`
Meta any `json:"meta,omitempty"`
}
Error represents a JSON:API error object as defined by https://jsonapi.org/format/1.1/#error-objects.
func (*Error) MarshalJSON ¶ added in v0.4.0
MarshalJSON implements the json.Marshaler interface.
func (*Error) UnmarshalJSON ¶ added in v0.7.2
UnmarshalJSON implements the json.Unmarshaler interface.
type ErrorLink ¶
ErrorLink represents a JSON:API error links object as defined by https://jsonapi.org/format/1.1/#error-objects.
type ErrorSource ¶
type ErrorSource struct {
Pointer string `json:"pointer,omitempty"`
Parameter string `json:"parameter,omitempty"`
Header string `json:"header,omitempty"`
}
ErrorSource represents a JSON:API Error.Source as defined by https://jsonapi.org/format/1.1/#error-objects.
type Link ¶
type Link struct {
Self any `json:"self,omitempty"`
Related any `json:"related,omitempty"`
First string `json:"first,omitempty"`
Last string `json:"last,omitempty"`
Next string `json:"next,omitempty"`
// Previous is deprecated and kept for backwards compatibility. Instead, use the Prev field.
Previous string `json:"previous,omitempty"`
Prev string `json:"prev,omitempty"`
}
Link is the top-level links object as defined by https://jsonapi.org/format/1.0/#document-top-level. First|Last|Next|Prev are provided to support pagination as defined by https://jsonapi.org/format/1.0/#fetching-pagination.
type LinkObject ¶
LinkObject is a links object as defined by https://jsonapi.org/format/1.0/#document-links
type Linkable ¶
type Linkable interface {
Link() *Link
}
Linkable can be implemented to marshal resource object links as defined by https://jsonapi.org/format/1.0/#document-resource-object-links.
type LinkableRelation ¶
LinkableRelation can be implemented to marshal resource object related resource links as defined by https://jsonapi.org/format/1.0/#document-resource-object-related-resource-links.
type MarshalIdentifier ¶
type MarshalIdentifier interface {
MarshalID() string
}
MarshalIdentifier can be optionally implemented to control marshaling of the primary field to a string.
The order of operations for marshaling the primary field is:
- Use MarshalIdentifier if it is implemented
- Use the value directly if it is a string
- Use fmt.Stringer if it is implemented
- Fail
type MarshalOption ¶
type MarshalOption func(m *Marshaler)
MarshalOption allows for configuration of Marshaling.
func MarshalClientMode ¶ added in v0.2.0
func MarshalClientMode() MarshalOption
MarshalClientMode enables client mode which skips validation only relevant for servers writing JSON:API responses.
func MarshalFields ¶
func MarshalFields(query url.Values) MarshalOption
MarshalFields supports sparse fieldsets as defined by https://jsonapi.org/format/1.0/#fetching-sparse-fieldsets. The input is a url.Values and if given only the fields included in `fields[type]=a,b` are included in the response.
func MarshalInclude ¶
func MarshalInclude(v ...any) MarshalOption
MarshalInclude includes the json:api encoding of v within Document.Included creating a compound document as defined by https://jsonapi.org/format/#document-compound-documents.
func MarshalJSONAPI ¶
func MarshalJSONAPI(meta any) MarshalOption
MarshalJSONAPI includes the given meta (must be a map or struct) as Document.JSONAPI.Meta when marshaling. This also enables writing Document.JSONAPI.Version.
func MarshalLinks ¶
func MarshalLinks(l *Link) MarshalOption
MarshalLinks includes the given links as Document.Links when marshaling.
func MarshalMeta ¶
func MarshalMeta(meta any) MarshalOption
MarshalMeta includes the given meta (must be a map or struct) as Document.Meta when marshaling.
func MarshalSetNameValidation ¶ added in v0.8.0
func MarshalSetNameValidation(mode MemberNameValidationMode) MarshalOption
MarshalSetNameValidation enables a given level of document member name validation.
func MarshallCheckUniqueness ¶ added in v0.12.0
func MarshallCheckUniqueness() MarshalOption
MarshallCheckUniqueness enables checking for unique resources during marshaling.
type MarshalType ¶ added in v0.13.0
type MarshalType interface {
MarshalType() string
}
MarshalType can be optionally implemented to control marshaling of the type field.
The order of operations for marshaling the type field is:
- Use MarshalType if it is implemented
- Use the value from the jsonapi tag on the primary field
- Fail
type Marshaler ¶
type Marshaler struct {
// contains filtered or unexported fields
}
Marshaler is configured internally via MarshalOption's passed to Marshal. It's used to configure the Marshaling by including optional fields like Meta or JSONAPI.
type MemberNameValidationError ¶ added in v0.5.0
type MemberNameValidationError struct {
MemberName string
}
MemberNameValidationError indicates that a document member name failed a validation step.
func (*MemberNameValidationError) Error ¶ added in v0.5.0
func (e *MemberNameValidationError) Error() string
Error implements the error interface.
type MemberNameValidationMode ¶ added in v0.8.0
type MemberNameValidationMode int
MemberNameValidationMode controls how document member names are checked for correctness.
const ( // DefaultValidation verifies that member names are valid according to the spec in // https://jsonapi.org/format/#document-member-names. // // Note that this validation mode allows for non-URL-safe member names. DefaultValidation MemberNameValidationMode = iota // DisableValidation turns off member name validation for convenience or performance-saving // reasons. // // Note that this validation mode allows member names that do NOT conform to the JSON:API spec. DisableValidation // StrictValidation verifies that member names are valid according to the spec in // https://jsonapi.org/format/#document-member-names, and follow recommendations from // https://jsonapi.org/recommendations/#naming. // // Note that these names are always URL-safe. StrictValidation )
type PartialLinkageError ¶
type PartialLinkageError struct {
// contains filtered or unexported fields
}
PartialLinkageError indicates that an incomplete relationship chain was encountered.
func (*PartialLinkageError) Error ¶
func (e *PartialLinkageError) Error() string
Error implements the error interface.
type UnmarshalIdentifier ¶
UnmarshalIdentifier can be optionally implemented to control unmarshaling of the primary field from a string.
The order of operations for unmarshaling the primary field is:
- Use UnmarshalIdentifier if it is implemented
- Use the value directly if it is a string
- Fail
type UnmarshalOption ¶
type UnmarshalOption func(m *Unmarshaler)
UnmarshalOption allows for configuration of Unmarshaling.
func UnmarshalCheckUniqueness ¶ added in v0.12.0
func UnmarshalCheckUniqueness() UnmarshalOption
UnmarshalCheckUniqueness enables checking for unique resources during unmarshaling.
func UnmarshalLinks ¶ added in v0.10.0
func UnmarshalLinks(link *Link) UnmarshalOption
UnmarshalLinks copies the Document.Links into the given link.
func UnmarshalMeta ¶
func UnmarshalMeta(meta any) UnmarshalOption
UnmarshalMeta decodes Document.Meta into the given interface when unmarshaling.
Example ¶
package main
import (
"fmt"
"github.com/DataDog/jsonapi"
)
func main() {
body := `{"data":{"id":"1","type":"articles","attributes":{"title":"Hello World"},"meta":{"views":10}},"meta":{"foo":"bar"}}`
type ArticleMeta struct {
Views int `json:"views"`
}
type Article struct {
ID string `jsonapi:"primary,articles"`
Title string `jsonapi:"attribute" json:"title"`
Meta *ArticleMeta `jsonapi:"meta"`
}
var (
a Article
m map[string]any
)
err := jsonapi.Unmarshal([]byte(body), &a, jsonapi.UnmarshalMeta(&m))
if err != nil {
panic(err)
}
fmt.Printf("%s %s %+v %+v", a.ID, a.Title, a.Meta, m)
}
Output: 1 Hello World &{Views:10} map[foo:bar]
func UnmarshalSetNameValidation ¶ added in v0.8.0
func UnmarshalSetNameValidation(mode MemberNameValidationMode) UnmarshalOption
UnmarshalSetNameValidation enables a given level of document member name validation.
type UnmarshalType ¶ added in v0.13.0
UnmarshalType can be optionally implemented to control unmarshaling of the type field from a string. Since the type is not typically set as a field on the object, this is an opportunity to return an error if the passed in type from the payload is unexpected. This allows customization of the expected type field.
The order of operations for checking the type field is:
- Use UnmarshalType if it is implemented, fail if it returns an error
- Compare against the type provided in the jsonapi tag on the primary field
- Fail
type Unmarshaler ¶
type Unmarshaler struct {
// contains filtered or unexported fields
}
Unmarshaler is configured internally via UnmarshalOption's passed to Unmarshal. It's used to configure the Unmarshaling by decoding optional fields like Meta.