Documentation ¶
Overview ¶
Package jsonapi provides utilities for converting Go data to/from the JSON API format detailed at http://jsonapi.org.
Consider an example, some structs representing a simple backend for a blog engine:
type Person { ID int Name string Age int } type Article struct { ID int Title string Body string Created time.Time Updated time.Time Author *Person }
The article data could be represented in a JSON format in compliance with the JSON API specification like so:
{ "id": "...", "type": "articles", "attributes": { "title": "...", "body": "...", "created": "...", "updated": "..." }, "relationships": { "author": { ... } }, "links": { ... }, "meta": { ... } }
In order to expose the article's data in the desired format, the some methods must be implemented to satisfy the expected interfaces for converting to/from resources. For a full list of supported interfaces as well as tested examples, please see the documentation for ToResource and FromResource.
Index ¶
Examples ¶
Constants ¶
const MediaType string = "application/vnd.api+json"
MediaType is the required media type for the exchange of data by the JSON API specification.
Variables ¶
This section is empty.
Functions ¶
func FromResource ¶
FromResource uses the adapter implementation v to set the values from the corresponding Resource r.
Several adapter interfaces are used to convert a Resource to a custom type; one is required and the rest are optional.
type identityWriteAdapter interface { SetID(string) error SetType(string) error }
The identity write adapter is used to populate the ID field on custom type from the Resource. It is required that all custom types implement this interface or FromResource will return an error.
type attributesWriteAdapter interface { SetAttributes(map[string]interface{}) error }
The attributes write adapter is used to populate fields on the custom type from the Attributes on the Resource. It is optional and will be ignored if not implemented, or if it returns nil.
type relationshipsWriteAdapter interface { SetRelationships(jsonapi.Relationships) error }
The relationships write adapter is used to populate fields on the custom type from the Relationships on the Resource. It is optional and will be ignored if not implemented, or if it returns nil.
Note the lack of a linksWriteAdapter and metaWriteAdapter, or a SetType method on the identityWriterAdapter. As per the JSON API specification for client interaction with an API (including reading, creating, updating or deleting any resources or relationships), these adapters should be unnecessary.
Example ¶
This example includes an integration test with jsonapi.FromResource function and the json.Unmarshal function from the "encoding/json" package.
testArticleJSON = ` { "id": "1", "type": "articles", "attributes": { "title": "JSON API paints my bikeshed!", "body": "The shortest article. Ever." }, "relationships": { "author": { "data": { "id": "42", "type": "people" }, "links": { "self": "http://example.com/articles/1/relationships/author", "related": "http://example.com/articles/1/author" } } }, "links": { "self": "http://example.com/articles/1" }, "meta": { "total": 42, "type": "foo" } } ` p := Person{} article := Article{} articleResource := jsonapi.Resource{} personResource := jsonapi.Resource{} // first, unmarshal and convert article resource to article if err := json.Unmarshal([]byte(testArticleJSON), &articleResource); err != nil { panic(err) } if err := jsonapi.FromResource(&article, &articleResource, true); err != nil { panic(err) } // person resource in author relationship must be unmarshaled separately afterwards if rel, ok := articleResource.Relationships.Get("author"); ok { if err := json.Unmarshal(rel.Data, &personResource); err != nil { panic(err) } if err := jsonapi.FromResource(&p, &personResource, true); err != nil { panic(err) } } article.Author = &p fmt.Println(article.ID, article.Title, article.Author.ID)
Output: 1 JSON API paints my bikeshed! 42
Types ¶
type Document ¶
type Document struct { Data json.RawMessage `json:"data,omitempty"` Errors []Error `json:"errors,omitempty"` Meta map[string]interface{} `json:"meta,omitempty"` Info *Info `json:"jsonapi,omitempty"` Links Links `json:"links,omitempty"` Included []Resource `json:"included,omitempty"` }
Document represents top-level document at the root of any JSON API request/response containing data.
type Error ¶
type Error struct { ID string `json:"id,omitempty"` Status string `json:"status,omitempty"` Code string `json:"code,omitempty"` Title string `json:"title,omitempty"` Detail string `json:"detail,omitempty"` Links Links `json:"links,omitempty"` Meta map[string]interface{} `json:"meta,omitempty"` }
Error represents a JSON API error object.
type Info ¶
type Info struct { Version string `json:"version"` Meta map[string]interface{} `json:"meta,omitempty"` }
Info represents a JSON API Object, used as the "jsonapi" member in the top-level document, which provides information about its implementation.
type Link ¶
Link represents a JSON API link object, which includes the required "href" key and optional "meta" key.
type Links ¶
type Links map[string]interface{}
Links represents a JSON API links object, which can include JSON API link objects or strings representing links.
http://jsonapi.org/format/#document-links
func (Links) Add ¶
Add adds the object key, value pair to the meta object. It overwrites any existing values associated with key.
func (Links) AddString ¶
AddString adds the string key, value pair to the meta object. It overwrites any existing values associated with key.
type Relationship ¶
type Relationship struct { Links Links `json:"links,omitempty"` Data json.RawMessage `json:"data,omitempty"` Meta map[string]interface{} `json:"meta,omitempty"` }
Relationship represents a member of the JSON API relationships object.
type Relationships ¶
type Relationships map[string]*Relationship
Relationships represents a JSON API relationships object
http://jsonapi.org/format/#document-resource-object-relationships
func (Relationships) Add ¶
func (rs Relationships) Add(key string, r *Relationship)
Add adds the key, value pair to the meta object. It overwrites any existing values associated with key.
func (Relationships) Delete ¶
func (rs Relationships) Delete(key string)
Delete deletes the value associated with the given key.
func (Relationships) Get ¶
func (rs Relationships) Get(key string) (*Relationship, bool)
Get returns the value associated with the given key and an existence check.
type Resource ¶
type Resource struct { ID string `json:"id"` Type string `json:"type"` Attributes map[string]interface{} `json:"attributes,omitempty"` Relationships Relationships `json:"relationships,omitempty"` Links Links `json:"links,omitempty"` Meta map[string]interface{} `json:"meta,omitempty"` }
Resource represents a JSON API resource identifier or resource object. Each valid JSON API resource object must contain at least the "id" and "type" keys, and may contain the optional "attributes", "relationships", "links" and "meta" keys.
Note that any of the optional keys will be omitted if a value is not provided.
For more information, see the specification at:
http://jsonapi.org/format/#document-resource-object
http://jsonapi.org/format/#document-resource-identifier-objects
func ToResource ¶
ToResource uses the adapter implementation v to return the corresponding Resource.
If full is true, ToResource will attempt to set the resource object's optional members including Attributes, Links and Meta. If full is false, the resultant resource object will only include the ID and Type members, allowing it to be used as a resource identifier object.
Several adapter interfaces are used to convert a custom type to a Resource; one is required and the rest are optional.
type identityReadAdapter interface { GetID() (string, error) GetType() (string, error) }
The identity read adapter is used to populate the ID and Type fields on the resultant Resource. It is required that all custom types implement this interface or ToResource will return an error.
type attributesReadAdapter interface { GetAttributes() (map[string]interface{}, error) }
The attributes read adapter is used to populate the Attributes field on the resultant Resource. It is optional and will be ignored if not implemented, or if it returns nil.
type relationshipsReadAdapter interface { GetRelationships() (jsonapi.Relationships, error) }
The relationships read adapter is used to populate the Relationships field on the resultant Resource. It is optional and will be ignored if not implemented, or if it returns nil.
type linksReadAdapter interface { GetLinks() (jsonapi.Links, error) }
The links read adapter is used to populate the Links field on the resultant Resource. It is optional and will be ignored if not implemented, or if it returns nil.
type metaReadAdapter interface { GetMeta() (map[string]interface{}, error) }
The meta read adapter is used to populate the Meta field on the resultant Resource. It is optional and will be ignored if not implemented, or if it returns nil.
Example ¶
This example includes an integration test with jsonapi.ToResource function and the json.Marshal function from the "encoding/json" package.
article := Article{ ID: 4, Title: "some title", Body: "some body", Author: &Person{ ID: 1, Name: "John", Age: 42, }, } // convert article to resource object resource, err := jsonapi.ToResource(&article, true) if err != nil { panic(err) } // then marshal resource using "encoding/json" package b, err := json.Marshal(&resource) if err != nil { panic(err) } fmt.Println(string(b))
Output: {"id":"4","type":"articles","attributes":{"body":"some body","title":"some title"},"relationships":{"author":{"links":{"related":"http://example.com/articles/1/author","self":"http://example.com/articles/1/relationships/author"},"data":{"id":"1","type":"people"}}},"links":{"self":"http://example.com/articles/1"},"meta":{"total":42,"type":"foo"}}