jsonapi

package module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 29, 2024 License: MIT Imports: 16 Imported by: 2

README

jsonapi

Test GoDoc Release

Yet Another JSON API library for Go.

Package jsonapi provides structures and functions to implement JSON API compatible APIs. The library can be used with any framework and is built on top of the standard Go http library.

Installation

Get the package using the go tool:

$ go get -u github.com/gonobo/jsonapi

Structures

This library uses StructField tags to annotate the structs fields that you already have and use in your app and then reads and writes JSON API output based on the tag content.

type Customer struct {
  ID   string `jsonapi:"primary,customers"`
  Name string `jsonapi:"attr,name"`
}

type Order struct {
  ID       string     `jsonapi:"primary,orders"`
  Customer *Customer  `jsonapi:"relation,customer"`
  Products []*Product `jsonapi:"relation,products,omitempty"`
}

type Product struct {
  ID string   `jsonapi:"primary,products"`
  Name string `jsonapi:"attr,name"`
}

// This object...
order := Order{
  ID:       "1",
  Customer: &Customer{ID: "2", Name: "John"},
  Products: []*Product{
    {ID: "42", Name: "Shoes"},
    {ID: "24", Name: "Socks"},
  }
}

// ...is transformed into this resource when marshaled.
resource := jsonapi.Resource{
  ID:   "1",
  Type: "orders",
  Relationships: jsonapi.Relationships{
    "customer": &jsonapi.Relationship{
      Data: jsonapi.One{
        Value: &jsonapi.Resource{
          ID:         "2",
          Type:       "customers",
          Attributes: map[string]any{"name": "John"},
        }}
    },
    "products": &jsonapi.Relationship{
      Data: jsonapi.Many{
        Values: []*jsonapi.Resource{
          {
            ID:         "42",
            Type:       "products",
            Attributes: map[string]any{"name": "Shoes"}
          },
          {
            ID:         "24",
            Type:       "products",
            Attributes: map[string]any{"name": "Socks"}
          },
        },
      },
    },
  }
}
Permitted Tag Values

Struct tag values are equivalent to those found in the Google JSON API library:

primary
`jsonapi:"primary,<type field output>"`

This indicates this is the primary key field for this struct type. Tag value arguments are comma separated. The first argument must be, primary, and the second must be the name that should appear in the type* field for all data objects that represent this type of model.

* According the JSON API spec, the plural record types are shown in the examples, but not required.

attr
`jsonapi:"attr,<key name in attributes hash>,<optional: omitempty>"`

These fields' values will end up in the attributeshash for a record. The first argument must be, attr, and the second should be the name for the key to display in the attributes hash for that record. The optional third argument is omitempty - if it is present the field will not be present in the "attributes" if the field's value is equivalent to the field types empty value (ie if the count field is of type int, omitempty will omit the field when count has a value of 0). Lastly, the spec indicates that attributes key names should be dasherized for multiple word field names.

relation
`jsonapi:"relation,<key name in relationships hash>,<optional: omitempty>"`

Relations are struct fields that represent a one-to-one or one-to-many relationship with other structs. JSON API will traverse the graph of relationships and marshal or unmarshal records. The first argument must be, relation, and the second should be the name of the relationship, used as the key in the relationships hash for the record. The optional third argument is omitempty - if present will prevent non existent to-one and to-many from being serialized.

Marshaling and Unmarshaling

All Marshal and Unmarshal methods expect pointers to struct instance or slices of the same type. Using values during marshaling and unmarshal is undefined behavior.

import "github.com/gonobo/jsonapi"

func createOrder(w *http.ResponseWriter, r *http.Request) {
  in, err := jsonapi.Decode(r.Body)
  order := Order{}
  err = jsonapi.Unmarshal(in, &order)

  newOrder, err := db.CreateNewOrder(order)
  out, err := jsonapi.Marshal(newOrder)
  w.WriteHeader(http.StatusCreated)
  err = jsonapi.Write(w, out)
}

JSON:API Server Handlers

This library also provides custom handlers to remove some of the boilerplate needed to adhere to the JSON:API specification.

import (
  "github.com/gonobo/jsonapi"
  "github.com/gonobo/jsonapi/mux"
)

func getOrder(r *http.Request) jsonapi.Response {
  // ctx contains the JSON:API information extracted from the http request:
  // - request type
  // - request id
  // - relationship name
  // - unmarshaled payload
  ctx, ok := jsonapi.GetContext(r.Context())

  order, err := db.GetOrder(ctx.ResourceID)
  out, err := jsonapi.Marshal(order)
  res := jsonapi.NewResponse(http.StatusCreated)
  res.Body = out
  return res
}

func main() {
  m := mux.New(
    mux.WithRoute("orders", mux.Route{
      // GET requests to /orders/:id will be routed to this handler.
      Get: jsonapi.HandlerFunc(getOrder),
      // GET requests to /orders will be routed to this handler.
      List: jsonapi.HandlerFunc(listOrders),
      // all other requests will return 404.
    })
    mux.WithRoute("customers", ...),
    mux.WithRoute("products", ...),
  )

  // Handler(h, ...opts) provides the request context using a default
  // request context resolver. This behavior can be modified via options.
  log.Fatal(http.ListenAndServe(":3333", jsonapi.Handler(m)))
}

Route also implements jsonapi.Handler, so you skip using Mux if you don't need it. This could be useful in serverless scenarios whose compute only serves a specific resource or operation:


jsonapi.Handler(mux.Route{
  Get: jsonapi.HandlerFunc(getOrder),
})

// OR

jsonapi.Handler(jsonapi.HandlerFunc(getOrder),
  func(h *jsonapi.H) {
    h.RequestContextResolver = MyCustomContextResolver()
  },
)

Examples

TBD.

License

The MIT License (MIT)

Copyright (c) 2024 Nathan Simpson

Documentation

Index

Constants

View Source
const LatestSupportedVersion = "1.1"
View Source
const (
	MediaType = "application/vnd.api+json"
)

Variables

View Source
var (
	ErrJSONAPI = errors.New("jsonapi error")
)

Functions

func Decode

func Decode(r io.Reader, doc *Document) error

Decode reads the JSON-encoded document from its input and stores it in the input document.

func Encode

func Encode(w io.Writer, doc *Document) error

Encode writes the JSON encoding of v to the stream, followed by a newline character.

func Handler

func Handler(handler RequestHandler, options ...func(*H)) http.Handler

Handler wraps JSON:API handlers such that they can be used as standard library http.Handler instances.

func MarshalRaw

func MarshalRaw(value any) (*json.RawMessage, error)

MarshalRaw serializes the input value to its JSON equivalent, wrapped in a RawMessage type for ease of use. Typically used for marshaling extensions within a JSON:API document.

func RequestWithContext

func RequestWithContext(r *http.Request, c *RequestContext) *http.Request

RequestWithContext sets the request context on the provided request.

func Send

func Send(r Request, options ...func(*http.Request)) (*http.Response, error)

Send sends a request to the server.

func SetContext

func SetContext(ctx context.Context, value *RequestContext) context.Context

SetContext sets the JSON:API Context in the parent context.

func Unmarshal added in v0.2.0

func Unmarshal(doc *Document, out any) error

Unmarshal populates the output struct or slice with information stored inside the provided document. Struct fields must either be properly tagged with "jsonapi:" or the struct must implement the UnmarshalResourceJSONAPI() method.

func UnmarshalResource

func UnmarshalResource(node *Resource, out any) error

UnmarshalResource populates the output struct's fields with information stored inside the provided resource node. Fields must either be properly tagged with "jsonapi:" or the struct must implement the UnmarshalJSONAPI() method.

func ValidateSpec added in v0.4.0

func ValidateSpec(doc *Document) error

Types

type Comparator

type Comparator interface {
	// Compare compares the values of the specified attribute for the
	// two resources at the specified indexes. If the two values are
	// equivalent, then Compare() should return 0. If the first value is
	// greater than the second value, then Compare() should return a
	// positive value. If the first value is less than the second value,
	// then Compare() should return a negative value.
	Compare(i, j int, attribute string) int
}

Comparator compares two resources and determines ordinality by comparing the values of a specified attribute.

func ResourceComparator added in v0.5.0

func ResourceComparator[S ~[]T, T any](arr S, m map[string]Comparer[T]) Comparator

ResourceComparator returns a Comparator that compares two resources a and b based on an attribute specified by the key index of map m.

type ComparatorFunc added in v0.5.0

type ComparatorFunc func(i, j int, attribute string) int

ComparatorFunc functions implement Comparator.

func (ComparatorFunc) Compare added in v0.5.0

func (f ComparatorFunc) Compare(i, j int, attribute string) int

Compare compares items indexed at i and j, returning negative if less, positive if greater, or zero if equal.

type Comparer added in v0.5.0

type Comparer[T any] func(a, b T) int

Comparer determines the order of two items.

type DefaultJSONEncoder

type DefaultJSONEncoder struct{}

DefaultJSONEncoder is a wrapper that implements JSONEncoder by calling:

json.NewEncoder(w).Encode(value).

func (DefaultJSONEncoder) EncodeJSON

func (DefaultJSONEncoder) EncodeJSON(w io.Writer, value any) error

EncodeJSON encodes the provided value to JSON.

type Document

type Document struct {
	Jsonapi           JSONAPI                     // The JSON:API object.
	Data              PrimaryData                 // The primary data.
	Meta              Meta                        // Top-level metadata.
	Links             Links                       // Top-level links.
	Errors            []*Error                    // Server response errors.
	Included          []*Resource                 // Included resources associated with the primary data.
	Extensions        map[string]*json.RawMessage // Optional JSON:API extensions.
	ValidateOnMarshal bool                        // Optional verification according to the JSON:API specification
}

Document is the highest order node, containing either a single resource or collection of resources in response to a client request. Clients also send documents to a server to create or modify existing resources.

func Marshal

func Marshal(in any) (Document, error)

Marshal generates a JSON:API document from the specified value. If the value is a struct, then a single document is returned, using the value as primary data. If the value is a slice or array, then a many document is returned, using the value as primary data.

Marshaling Document structs simply returns a copy of the instance.

func MarshalRef

func MarshalRef(in any, name string) (Document, error)

MarshalRef generates a JSON:API document, using a resource's relationship as primary data. It otherwise functions in the same manner as Marshal().

func NewMultiDocument

func NewMultiDocument(data ...*Resource) *Document

NewMultiDocument creates a new document with the provided resources as primary data.

func NewSingleDocument

func NewSingleDocument(data *Resource) *Document

NewSingleDocument creates a new document with the provided resource as primary data.

func (*Document) ApplyVisitor

func (d *Document) ApplyVisitor(v *Visitor) error

ApplyVisitor allows the provided visitor to traverse this document.

func (Document) Error

func (d Document) Error() error

Error calls errors.Join() on all errors within the document. It returns a single error if any errors were present or nil otherwise.

func (Document) MarshalJSON

func (d Document) MarshalJSON() ([]byte, error)

MarshalJSON serializes the document as JSON.

func (*Document) Sort

func (d *Document) Sort(cmp Comparator, criterion []query.Sort)

Sort sorts the document's primary data by comparing the resources against the provided sort criterion.

func (*Document) UnmarshalJSON

func (d *Document) UnmarshalJSON(data []byte) error

UnmarshalJSON deserializes the document from JSON, populating its contents.

type DocumentVisitor

type DocumentVisitor interface {
	// VisitDocument visits the document. Return an error to stop visiting.
	VisitDocument(obj *Document) error
}

DocumentVisitor visits JSON:API document nodes.

type Doer

type Doer interface {
	// Do sends an HTTP request and returns an HTTP response.
	Do(*http.Request) (*http.Response, error)
}

Doer is responsible for sending HTTP requests. The Golang http.Client struct implements this interface.

type Error

type Error struct {
	ID     string       `json:"id,omitempty"`     // A unique identifier for this particular occurrence of the problem.
	Links  Links        `json:"links,omitempty"`  // A links object associated with the error.
	Status string       `json:"status,omitempty"` // The HTTP status code applicable to this problem.
	Code   string       `json:"code,omitempty"`   // An application-specific error code.
	Title  string       `json:"title,omitempty"`  // A short summary of the problem.
	Detail string       `json:"detail,omitempty"` // A specific explanation of the problem.
	Source *ErrorSource `json:"source,omitempty"` // An object containing references to the primary source of the error.
	Meta   Meta         `json:"meta,omitempty"`   // Contains non-standard meta-information about the error.
}

Error provides additional information about problems encountered while performing an operation. Error objects MUST be returned as an array keyed by errors in the top level of a JSON:API document.

func NewError

func NewError(cause error, title string) Error

NewError creates a new ErrorNode with the given status and title.

func (Error) Error

func (e Error) Error() string

Error returns the combined title and detail as a single message.

type ErrorSource

type ErrorSource struct {
	// A JSON Pointer [RFC6901] to the value in the request document
	// that caused the error [e.g. "/data" for a primary data object,
	// or "/data/attributes/title" for a specific attribute].
	Pointer string `json:"pointer,omitempty"`

	Parameter string `json:"parameter,omitempty"` // URI query parameter that caused the error.
	Header    string `json:"header,omitempty"`    // Name of a single request header which caused the error.
}

ErrorSource is an object containing references to the primary source of the error.

type ErrorVisitor

type ErrorVisitor interface {
	// VisitError visits the error node. Return an error to stop visiting.
	VisitError(obj *Error) error
}

ErrorVisitor visits JSON:API error nodes.

type ExtensionsNode

type ExtensionsNode = map[string]*json.RawMessage

ExtensionsNode contains data defined by JSON:API extensions. Since they can be arbitrary, they are stored as raw JSON messages to be serialized by the caller.

type H

type H struct {
	RequestContextResolver // The JSON:API context resolver.
	// contains filtered or unexported fields
}

H is an adapter to allow the use of JSON:API handlers as HTTP handlers.

func (H) ServeHTTP

func (h H) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements the http.Handler interface.

type HandlerFunc

type HandlerFunc func(*http.Request) Response

HandlerFunc is an adapter to allow the use of ordinary functions as JSON:API handlers. If f is a function with the appropriate signature, HandlerFunc(f) is a Handler that calls f.

func (HandlerFunc) RouteJSONAPI

func (f HandlerFunc) RouteJSONAPI(ctx *RequestContext, r *http.Request) Response

RouteJSONAPI routes a JSON:API request to the handler function.

func (HandlerFunc) ServeJSONAPI

func (f HandlerFunc) ServeJSONAPI(r *http.Request) Response

ServeJSONAPI calls f(r).

type HrefLang

type HrefLang []string

HrefLang is a string or an array of strings indicating the language(s) of the link’s target. An array of strings indicates that the link’s target is available in multiple languages. Each string MUST be a valid language tag [RFC5646].

HrefLang is serialized as a string if there is only one element within the slice, or an array of strings otherwise.

func (HrefLang) MarshalJSON

func (h HrefLang) MarshalJSON() ([]byte, error)

MarshalJSON provides custom JSON deserialization.

func (*HrefLang) UnmarshalJSON

func (h *HrefLang) UnmarshalJSON(data []byte) error

UnmarshalJSON provides custom JSON deserialization.

type JSONAPI

type JSONAPI struct {
	Version Version        `json:"version"`           // The highest specification version supported by the server.
	Ext     []string       `json:"ext,omitempty"`     // An array of URIs for all applied extensions.
	Profile []string       `json:"profile,omitempty"` // An array of URIs for all applied profiles.
	Meta    map[string]any `json:"meta,omitempty"`    // Metadata containing non-standard information.
}

JSONAPI includes information about the server's implementation. See https://jsonapi.org/format/#document-jsonapi-object for details.

type JSONEncoder

type JSONEncoder interface {
	// EncodeJSON encodes the provided value to JSON.
	EncodeJSON(w io.Writer, value any) error
}

JSONEncoder is responsible for encoding JSON data. It is primarily used for dependency injection during unit testing.

type Link struct {
	Href     string   // URI-reference pointing to the link’s target.
	Rel      string   // The link’s relation type.
	Type     string   // The media type of the link’s target.
	Title    string   // Human-readable link destination.
	HrefLang HrefLang // Array of strings indicating the link's target language(s).
	Meta     Meta     // Contains non-standard meta-information about the link.
}

Link represents a single link.

func (Link) MarshalJSON

func (l Link) MarshalJSON() ([]byte, error)

MarshalJSON serializes this link to JSON.

func (*Link) UnmarshalJSON

func (l *Link) UnmarshalJSON(data []byte) error

UnmarshalJSON deserializes this link from JSON.

type Links = map[string]*Link

Links contains the links defined within a resource, document, or error.

type LinksMarshaler

type LinksMarshaler interface {
	// MarshalLinksJSONAPI returns links associated with the instance when marshaled.
	MarshalLinksJSONAPI() Links
}

LinksMarshaler creates links associated with the instance when marshaled.

type LinksUnmarshaler

type LinksUnmarshaler interface {
	// UnmarshalLinksJSONAPI extracts links from a resource node and populates itself.
	UnmarshalLinksJSONAPI(Links)
}

LinksUnmarshaler can extract links from a resource node and populate itself.

type LinksVisitor

type LinksVisitor interface {
	// VisitLinks visits the links. Return an error to stop visiting.
	VisitLinks(obj Links) error
	// VisitLink visits a link. Return an error to stop visiting.
	VisitLink(obj *Link) error
}

LinksVisitor visits JSON:API link nodes.

type Many

type Many struct {
	Value []*Resource `json:"-"` // Value is the collection of resources.
}

Many is a data node that represents a "to-many" relationship or a document's primary data.

func (Many) First added in v0.3.0

func (m Many) First() *Resource

First returns the first item in the array of resources.

func (Many) IsMany

func (Many) IsMany() bool

IsMany returns true, as this is a "to-many" relationship.

func (Many) Items

func (m Many) Items() []*Resource

Items returns the underlying value collection.

func (Many) MarshalJSON

func (m Many) MarshalJSON() ([]byte, error)

MarshalJSON serializes the node to JSON.

func (*Many) UnmarshalJSON

func (m *Many) UnmarshalJSON(data []byte) error

UnmarshalJSON deserializes the node from JSON.

type Meta

type Meta = map[string]any

Meta contains non-standard information within a document.

type MetaMarshaler

type MetaMarshaler interface {
	// MarshalMetaJSONAPI returns metadata associated with the instance when marshaled.
	MarshalMetaJSONAPI() Meta
}

MetaMarshaler creates metadata associated with the instance when marshaled.

type MetaUnmarshaler

type MetaUnmarshaler interface {
	// UnmarshalMetaJSONAPI extracts metadata from a resource node and populates itself.
	UnmarshalMetaJSONAPI(Meta)
}

MetaUnmarshaler can extract metadata from a resource node and populate itself.

type MetaVisitor

type MetaVisitor interface {
	// VisitMeta visits the meta node. Return an error to stop visiting.
	VisitMeta(obj Meta) error
}

MetaVisitor visits JSON:API meta nodes.

type Middleware

type Middleware func(next RequestHandler) RequestHandler

Middleware is a function that takes a Handler and returns a Handler.

func Passthrough

func Passthrough() Middleware

Passthrough creates a middleware function that returns the next handler.

func (Middleware) Use

func (fn Middleware) Use(middleware Middleware) Middleware

Use appends the provided middleware to the current middleware chain.

func (Middleware) Wrap

func (fn Middleware) Wrap(handler RequestHandler) RequestHandler

Wrap wraps the provided handler with the current middleware chain.

type One

type One struct {
	Value *Resource `json:"-"` // Value is the single resource.
}

One is a data node that represents either a "to-one" relationship or a document's primary data.

func (One) First added in v0.3.0

func (o One) First() *Resource

First returns the resource value (if present) or nil.

func (One) IsMany

func (One) IsMany() bool

IsMany returns false, as this is a "to-one" relationship.

func (One) IsNull

func (o One) IsNull() bool

IsNull returns true if the node value is nil.

func (One) Items

func (o One) Items() []*Resource

Items returns the underlying value in a collection.

func (One) MarshalJSON

func (o One) MarshalJSON() ([]byte, error)

MarshalJSON serializes the node to JSON.

func (*One) UnmarshalJSON

func (o *One) UnmarshalJSON(data []byte) error

UnmarshalJSON deserializes the node from JSON.

type PartialVisitor

type PartialVisitor struct {
	Document      VisitorFunc[*Document]         // Function for visiting document nodes.
	Links         VisitorFunc[Links]             // Function for visiting links nodes.
	Link          VisitorFunc[*Link]             // Function for visiting link nodes.
	Meta          VisitorFunc[Meta]              // Function for visiting meta nodes.
	Resource      VisitorFunc[*Resource]         // Function for visiting resource nodes.
	Relationship  VisitorFunc[*Relationship]     // Function for visiting relationship nodes.
	Relationships VisitorFunc[RelationshipsNode] // Function for visiting relationships nodes.
	Ref           VisitorFunc[*Resource]         // Function for visiting resource nodes referenced in relationships.
	Error         VisitorFunc[*Error]            // Function for visiting error nodes.
}

PartialVisitor can visit chosen nodes while ignoring others. For example, if you only want to visit the document node and its top links, you can use this to create a visitor that only visits the document node. If you want to visit all link nodes, add link visitor instead.

func (PartialVisitor) VisitDocument

func (v PartialVisitor) VisitDocument(obj *Document) error

VisitDocument visits the document.

func (PartialVisitor) VisitError

func (v PartialVisitor) VisitError(obj *Error) error

VisitError visits the error node.

func (v PartialVisitor) VisitLink(obj *Link) error

VisitLink visits a link.

func (v PartialVisitor) VisitLinks(obj Links) error

VisitLinks visits the links.

func (PartialVisitor) VisitMeta

func (v PartialVisitor) VisitMeta(obj Meta) error

VisitMeta visits the meta node.

func (PartialVisitor) VisitRef

func (v PartialVisitor) VisitRef(obj *Resource) error

VisitRef visits the resource node referenced in a relationship.

func (PartialVisitor) VisitRelationship

func (v PartialVisitor) VisitRelationship(obj *Relationship) error

VisitRelationship visits the relationship node.

func (PartialVisitor) VisitRelationships

func (v PartialVisitor) VisitRelationships(obj RelationshipsNode) error

VisitRelationships visits the relationships node.

func (PartialVisitor) VisitResource

func (v PartialVisitor) VisitResource(obj *Resource) error

VisitResource visits the resource node.

func (*PartialVisitor) Visitor

func (v *PartialVisitor) Visitor() *Visitor

Visitor creates a visitor instance that can traverse a document.

type PrimaryData

type PrimaryData interface {
	// Items returns the contained items as a collection of resources.
	//	- If the data node represents a null "to-one" relationship, then the slice will be empty.
	//	- If the data node represents a "to-one" relationship, then the slice will contain the
	//		associated resource at the first index.
	//	- If the data node represents a "to-many" relationship, then the slice will contain
	//		the associated resources.
	Items() []*Resource
	// IsMany returns true if the data represents a "to-many" relationship or collection of primary data.
	IsMany() bool
	// First returns the first item in a primary data node -- the node itself for single or "one"
	// primary data, or the first element in multi or "many" primary data.
	//
	// If the data node is set to "null" (a jsonapi.One instance with a nil value) then nil is returned.
	// If the data node itself is nil, First() panics.
	First() *Resource
}

PrimaryData interfaces provide document primary data or resource relationship data. Since data can be either a single resource or a collection of resources, PrimaryData has helper functions to both identify and iterate over said resources.

type RelatedLinksMarshaler

type RelatedLinksMarshaler interface {
	// MarshalRelatedLinksJSONAPI returns links associated with an instance's relationships when marshaled.
	MarshalRelatedLinksJSONAPI(name string) Links
}

RelatedLinksMarshaler creates links associated with an instance's relationships when marshaled.

type RelatedLinksUnmarshaler

type RelatedLinksUnmarshaler interface {
	// UnmarshalRelatedLinksJSONAPI extracts relationship links from a node and populate itself.
	UnmarshalRelatedLinksJSONAPI(name string, links Links)
}

RelatedLinksUnmarshaler can extract relationship links from a node and populate itself.

type RelatedMetaMarshaler

type RelatedMetaMarshaler interface {
	// MarshalRelatedMetaJSONAPI returns metadata associated with an instance's relationships when marshaled.
	MarshalRelatedMetaJSONAPI(name string) Meta
}

RelatedMetaMarshaler creates metadata associated with an instance's relationships when marshaled.

type RelatedMetaUnmarshaler

type RelatedMetaUnmarshaler interface {
	// UnmarshalRelatedMetaJSONAPI extracts relationship metadata from a node and populates itself.
	UnmarshalRelatedMetaJSONAPI(name string, meta Meta)
}

RelatedMetaUnmarshaler can extract relationship metadata from a node and populate itself.

type Relationship

type Relationship struct {
	Data  PrimaryData // Relationship data containing associated references.
	Links Links       // URL links related to the relationship.
	Meta  Meta        // Non-standard information related to the relationship.
}

Relationship describes a resource's relationships. Relationships are contain either "to-many" or "to-one" associations with the parent resource. See https://jsonapi.org/format/#document-resource-object-relationships for details.

func (Relationship) MarshalJSON added in v0.5.0

func (r Relationship) MarshalJSON() ([]byte, error)

func (*Relationship) UnmarshalJSON

func (r *Relationship) UnmarshalJSON(data []byte) error

UnmarshalJSON deserializes this relationship from JSON.

type RelationshipVisitor

type RelationshipVisitor interface {
	// VisitRelationship visits the relationship node. Return an error to stop visiting.
	VisitRelationships(obj RelationshipsNode) error
	// VisitRelationship visits the relationship node. Return an error to stop visiting.
	VisitRelationship(obj *Relationship) error
	// VisitRelationship visits the resource node referenced in a relationship.
	// Return an error to stop visiting.
	VisitRef(obj *Resource) error
}

RelationshipVisitor visits JSON:API relationship nodes.

type RelationshipsNode

type RelationshipsNode = map[string]*Relationship

RelationshipsNode contains the relationships defined within a resource.

type Request

type Request struct {
	JSONEncoder                // The JSON encoder.
	URLResolver                // The URL resolver.
	BaseURL     string         // The base url of the JSON:API server.
	Client      Doer           // The underlying http client.
	Context     RequestContext // The JSON:API request context.
	Method      string         // The http method to use.
}

Request is a JSON:API http client. It uses an underlying standard library http client to send requests that adhere to the JSON:API specification.

By default, Request generates the following urls (given a base url):

":base/:type" for search, create
":base/:type/:id" for fetch, update, delete
":base/:type/:id/relationships/:ref" for fetchRef
":base/:type/:id/:ref" for fetchRelated

This behavior can be modified by updating the URLResolver field of a Request instance.

func NewRequest

func NewRequest(baseURL string, options ...func(*Request)) Request

NewRequest creates a new JSON:API request instance.

func (Request) AddRefsToMany

func (r Request) AddRefsToMany(data Resource, ref string, options ...func(*http.Request)) (*http.Response, error)

AddRefsToMany adds a server resource reference to the provided resource's "to-many" relationship.

func (Request) Create

func (r Request) Create(data Resource, options ...func(*http.Request)) (*http.Response, error)

Create creates a new server resource. If the resource has an empty string resource ID, then the server will assign it; otherwise, the id will be submitted in the request payload.

func (Request) Delete

func (r Request) Delete(resourceType, id string, options ...func(*http.Request)) (*http.Response, error)

Delete removes a resource from the server.

func (Request) Get

func (r Request) Get(resourceType, id string, options ...func(*http.Request)) (*http.Response, error)

Get retrieves a single resource from the server.

func (Request) GetRef

func (r Request) GetRef(resourceType, id, ref string, options ...func(*http.Request)) (*http.Response, error)

GetRef retrieves a single resource's relationship from the server.

func (Request) GetRelated

func (r Request) GetRelated(resourceType, id, relation string, options ...func(*http.Request)) (*http.Response, error)

GetRelated retrieves all server resources that are referenced in a resource's relationship.

func (Request) HTTPRequest

func (r Request) HTTPRequest() (*http.Request, error)

HTTPRequest generates a http.Request from a Request instance.

func (Request) List

func (r Request) List(resourceType string, options ...func(*http.Request)) (*http.Response, error)

List retrieves a collection of server resources associated with the resource type.

func (Request) RemoveRefsFromMany

func (r Request) RemoveRefsFromMany(data Resource, ref string, options ...func(*http.Request)) (*http.Response, error)

RemoveRefsFromMany removes a server resource reference to the provided resource's "to-many" relationship.

func (Request) Update

func (r Request) Update(data Resource, options ...func(*http.Request)) (*http.Response, error)

Update updates a new server resource.

func (Request) UpdateRef

func (r Request) UpdateRef(data Resource, ref string, options ...func(*http.Request)) (*http.Response, error)

UpdateRef replaces a single resource's relationship with the request data.

type RequestContext

type RequestContext struct {
	ResourceType string                 // The request resource type, e.g, "users".
	ResourceID   string                 // The request resource ID, e.g, "123".
	Relationship string                 // The request relationship, e.g, "posts".
	Related      bool                   // If true, the server should fetch the resources associated with the relationship.
	FetchIDs     []string               // If nonempty, the server should fetch the resources with these IDs.
	Include      []string               // The list of resources associated with the request resource that should be included in the response.
	Document     *Document              // The JSON:API document that defines the request payload.
	Fields       []query.Fieldset       // The list of fields (attributes, relationships, etc.) that should be included in the response payload
	Filter       query.FilterExpression // The filter expression that was evaluated from the request query.
	Sort         []query.Sort           // The sort criteria that was evaluated from the request query.
	Pagination   query.Page             // The pagination criteria that was evaluated from the request query.
	// contains filtered or unexported fields
}

RequestContext contains information about the JSON:API request that defines it.

RequestContext decouples information relevant to the specification, such as the resource type, unique identifier, relationships, etc. from the request itself.

func GetContext

func GetContext(parent context.Context) (*RequestContext, bool)

GetContext returns the JSON:API Context from the parent context. Returns false if the context has not been set, or if the context is nil.

func (*RequestContext) Child

func (c *RequestContext) Child() *RequestContext

Child returns a new Context that is a child of the current Context; the new child context contains the same information as its parent.

func (RequestContext) Clone

func (c RequestContext) Clone() *RequestContext

Clone returns a new Context that is a clone of the current Context.

func (*RequestContext) EmptyChild

func (c *RequestContext) EmptyChild() *RequestContext

EmptyChild returns a new Context that is a child of the current Context.

func (RequestContext) Parent

func (c RequestContext) Parent() *RequestContext

Parent returns the parent Context of the current Context.

func (RequestContext) Root

func (c RequestContext) Root() *RequestContext

Root returns the root Context of the current Context. That is, the top-most parent that has no parent of its own.

type RequestContextResolver

type RequestContextResolver interface {
	// ResolveContext resolves the JSON:API context from the provided http request.
	// The context informs downstream dependencies; at minimum, the context should
	// populate the following fields (if applicable):
	//	- ResourceType (the resource type being requested)
	//	- ResourceID (the unique identifier of the resource being requested)
	//	- Relationship (the relationship being requested)
	//	- Related (whether the relationship is a related resource)
	ResolveContext(*http.Request) (RequestContext, error)
}

RequestContextResolver resolves JSON:API context information from an incoming http request.

type RequestContextResolverFunc

type RequestContextResolverFunc func(*http.Request) (RequestContext, error)

RequestContextResolverFunc functions implement ContextResolver.

func DefaultRequestContextResolver

func DefaultRequestContextResolver() RequestContextResolverFunc

DefaultRequestContextResolver returns a resolver that populates a JSON:API context based on the URL path examples given by the JSON:API specification:

"/:type"                         // ResourceType
"/:type/:id"                     // ResourceType, ResourceID
"/:type/:id/relationships/:ref"  // ResourceType, ResourceID, Relationship
"/:type/:id/:ref"                // ResourceType, ResourceID, Relationship, Related

func (RequestContextResolverFunc) ResolveContext

func (fn RequestContextResolverFunc) ResolveContext(r *http.Request) (RequestContext, error)

ResolveContext resolves the JSON:API context from the provided http request.

type RequestHandler

type RequestHandler interface {
	// ServeJSONAPI handles a JSON:API request.
	ServeJSONAPI(*http.Request) Response
}

RequestHandler handles JSON:API requests.

type Resource

type Resource struct {
	ID            string            // ID is the unique identifier of the resource.
	LocalID       string            // LocalID is the unique identifier of the resource within the context of the document.
	Type          string            // Type is the type of resource.
	Attributes    map[string]any    // Attributes are the resource's attributes.
	Relationships RelationshipsNode // Relationships are the resource's relationships.
	Links         Links             // Links are the resource's associated URL links.
	Meta          Meta              // Meta contains any non-standard information about the resource.
	Extensions    ExtensionsNode    // Extensions contain any JSON:API extensions associated with the resource.
}

Resource represents a server resource. Resources can appear in documents as primary data, included resources, or referenced in other resources' relationships. See https://jsonapi.org/format/#document-resource-objects for details.

func First deprecated added in v0.1.0

func First(data PrimaryData) *Resource

First returns the first item in a primary data node -- the node itself for single or "one" primary data, or the first element in multi or "many" primary data.

If the data node is set to "null" (a jsonapi.One instance with a nil value) then nil is returned. If the data node itself is nil, First() panics.

Deprecated: First is deprecated and will be removed in the next major release. Use the First() method on the PrimaryData interface instead.

func MarshalResource

func MarshalResource(in any) (*Resource, error)

MarshalResource generates a JSON:API resource object based on the input struct's fields. Fields must be tagged with "jsonapi:" in order to be processed by the marshaler, or the struct type can implement MarshalResourceJSONAPI() to override the process.

func (Resource) MarshalJSON

func (r Resource) MarshalJSON() ([]byte, error)

MarshalJSON serializes this resource into JSON.

func (Resource) MarshalJSONAPI added in v0.2.0

func (r Resource) MarshalJSONAPI() (*Resource, error)

MarshalJSONAPI returns a shallow copy of this resource.

func (Resource) Ref

func (r Resource) Ref() *Resource

Ref returns a reference to this resource. Any non essential information -- information that is not required to identify the resource -- is omitted. Any resource metadata, however is included.

func (*Resource) UnmarshalJSON

func (r *Resource) UnmarshalJSON(data []byte) error

UnmarshalJSON deserializes this resource from JSON.

func (*Resource) UnmarshalJSONAPI added in v0.2.0

func (r *Resource) UnmarshalJSONAPI(other *Resource) error

UnmarshalJSONAPI extracts information from a resource node and populates itself.

type ResourceMarshaler

type ResourceMarshaler interface {
	// MarshalJSONAPI marshals this instance into a resource node.
	MarshalJSONAPI() (*Resource, error)
}

ResourceMarshaler can marshal its information into a resource node. Structs that implement this interface can override the default marshaling process.

type ResourceUnmarshaler

type ResourceUnmarshaler interface {
	// UnmarshalJSONAPI extracts information from a resource node and populates itself.
	UnmarshalJSONAPI(*Resource) error
}

ResourceUnmarshaler can extract information from a resource node and populate itself. This is an escape hatch from the default unmarshal process.

type ResourceVisitor

type ResourceVisitor interface {
	// VisitResource visits the resource node. Return an error to stop visiting.
	VisitResource(obj *Resource) error
}

ResourceVisitor visits JSON:API resource nodes.

type Response

type Response struct {
	Code    int               // The http status code.
	Headers map[string]string // Optional status headers.
	Body    *Document         // Optional response body.
}

Response objects contain the HTTP response status code, headers, and an optional body, formatted as a JSONAPI document.

A Response's zero value is usually invalid; use the NewResponse() function to properly initialize a Response object.

Response objects are used by the server to format the response to a client. A Response object can be marshaled to JSON and written to the HTTP response via the Write() method. Example:

r := jsonapi.NewResponse(func(res *jsonapi.Response) {
	res.Body = jsonapi.NewSingleDocument(...)
	res.Code = http.StatusOK
	res.Headers["my-header-key"] = "my-header-value"
})

r.Write(w) // flushed to http response

Response objects can also be used to format errors:

r := jsonapi.NewResponse(func(res *jsonapi.Response) {
	res.AppendError(errors.New("some error"))
	res.Code = http.StatusInternalServerError
})

func NewResponse

func NewResponse(status int, opts ...ResponseOption) Response

NewResponse returns a new JSONAPIResponse object. Use response options to modify or format the response header, status code, and body. Example:

response := jsonapi.NewResponse(
	server.Ok(&jsonapi.Document{ ... }),
	server.Header("my-header-key", "my-header-value"),
)

An unmodified response will return 204 No Content to the client.

func (*Response) AppendError

func (r *Response) AppendError(cause error)

func (*Response) ApplyOptions

func (r *Response) ApplyOptions(opts ...ResponseOption)

func (Response) WriteResponse

func (r Response) WriteResponse(w http.ResponseWriter, opts ...ResponseOption) (int, error)

WriteResponse writes the JSON:API response to the http response writer. The number value returned is always zero, and not indicative of the number of bytes written.

type ResponseOption

type ResponseOption = func(*Response)

type Specification added in v0.4.0

type Specification interface {
	// contains filtered or unexported methods
}

type SpecificationVersion added in v0.4.0

type SpecificationVersion string
const (
	Version1_1 SpecificationVersion = "1.1"
)

type URLResolver

type URLResolver interface {
	// ResolveURL creates a url based on the provided request context and base URL.
	ResolveURL(ctx RequestContext, baseURL string) string
}

URLResolver resolves urls based on the JSON:API request context.

type URLResolverFunc

type URLResolverFunc func(RequestContext, string) string

URLResolverFunc functions implement URLResolver.

func DefaultURLResolver

func DefaultURLResolver() URLResolverFunc

DefaultURLResolver returns a resolver that generates the following urls based on the request context (given a base url):

":base/:type" for search, create
":base/:type/:id" for fetch, update, delete
":base/:type/:id/relationships/:ref" for fetchRef
":base/:type/:id/:ref" for fetchRelated

func (URLResolverFunc) ResolveURL

func (fn URLResolverFunc) ResolveURL(ctx RequestContext, baseURL string) string

ResolveURL creates a url based on the provided request context and base URL.

type Version

type Version string

Version contains information regarding the JSON:API version supported by the server.

func (Version) MarshalJSON

func (v Version) MarshalJSON() ([]byte, error)

MarshalJSON serializes the version into JSON.

func (Version) Value added in v0.4.0

func (v Version) Value() string

Value returns the associated version, or the last version supported by this library if zero-value.

type Visitor

Visitor can traverse a JSON:API document tree. Use the subvisitors to inspect or modify the document in place.

type VisitorFunc

type VisitorFunc[Node any] func(Node) error

VisitorFunc can visit a node of the specified type.

Directories

Path Synopsis
internal
log
mux

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL