Package jsonapi implements a marshaler/unmarshaler for JSON:API v1.0.
This package is in production use at DataDog and should be considered stable and production ready.
We follow semver and are reserving the v1.0.0 release until:
- JSON:API v1.1 is released and we evaluate any breaking changes needed (unlikely)
- Community adoption and feedback are evaluated
- Continued internal use lets us gain more experience with the package
Take a look at the go reference for more examples and detailed usage information.
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 {
// ...
}
fmt.Println("%s", string(b))
// {
// "data": {
// "id": "1",
// "type": "articles",
// "attributes": {
// "title": "Hello World"
// }
// }
// }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
if err := jsonapi.Unmarshal([]byte(body), &a); err != nil {
// ...
}
fmt.Prints("%s, %s", a.ID, a.Title)
// "1", "Hello World"The following information is well documented in the go reference. This section is included for a high-level overview of the features available.
Like encoding/json jsonapi is primarily controlled by the presence of a struct tag jsonapi. The standard json tag is still used for naming and omitempty.
| Tag | Usage | Description | Alias |
|---|---|---|---|
| primary | jsonapi:"primary,{type},{omitempty}" |
Defines the identification field. Including omitempty allows for empty IDs (used for server-side id generation) | N/A |
| attribute | jsonapi:"attribute" |
Defines an attribute. | attr |
| relationship | jsonapi:"relationship" |
Defines a relationship. | rel |
| meta | jsonapi:"meta" |
Defines a meta object. | N/A |
Both jsonapi.Marshal and jsonapi.Unmarshal take functional options.
| Option | Supports |
|---|---|
| jsonapi.MarshalOption | meta, json:api, includes, document links, sparse fieldsets, name validation |
| jsonapi.UnmarshalOption | meta, document links, name validation |
Identification MUST be represented as a string regardless of the actual type in Go. To support non-string types for the primary field you can implement optional interfaces.
You can implement the following on the parent types (that contain non-string fields):
| Context | Interface |
|---|---|
| Marshal | jsonapi.MarshalIdentifier |
| Unmarshal | jsonapi.UnmarshalIdentifier |
You can implement the following on the field types themselves if they are not already implemented.
| Context | Interface |
|---|---|
| Marshal | fmt.Stringer |
| Marshal | encoding.TextMarshaler |
| Unmarshal | encoding.TextUnmarshaler |
- Use MarshalIdentifier if it is implemented on the parent type
- Use the value directly if it is a string
- Use fmt.Stringer if it is implemented
- Use encoding.TextMarshaler if it is implemented
- Fail
- Use UnmarshalIdentifier if it is implemented on the parent type
- Use encoding.TextUnmarshaler if it is implemented
- Use the value directly if it is a string
- Fail
JSON:API permits a resource identifier object in relationship data to contain a meta object. Implement jsonapi.MarshalResourceIdentifierMeta on the related resource type to add this object.
type Comment struct {
ID string `jsonapi:"primary,comments"`
Index int
}
func (c Comment) MarshalResourceIdentifierMeta() any {
return map[string]any{"index": c.Index}
}The marshaler uses this interface only for relationship data. Return nil to omit the meta member. The jsonapi:"meta" directive continues to control metadata on the relationship object.
Links are supported via two interfaces and the Link type. To include links you must implement one or both of the following interfaces.
| Type | Interface |
|---|---|
| Resource Object Link | Linkable |
| Resource Object Related Resource Link | LinkableRelation |
- exposes an API that looks/feels a lot different than encoding/json
- has quite a few bugs w/ complex types in attributes
- doesn't provide easy access to top-level fields like meta
- allows users to generate invalid JSON:API
- not actively maintained
- has required interfaces
- interfaces for includes/relationships are hard to understand and verbose to implement
- allows users to generate invalid JSON:API
- part of a broader api2go framework ecosystem