jsonapi

package module
v2.3.1 Latest Latest
Warning

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

Go to latest
Published: Jan 17, 2023 License: MIT Imports: 11 Imported by: 2

README

jsonapi

Test GoDoc Release

A fundamental and extendable 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.

Extensions

Custom Actions

The package supports the non-standard but widely adopted "custom actions" extension to support the following patterns:

GET /posts/highlighted
DELETE /posts/cache
POST /posts/1/publish
DELETE /posts/1/history
Cursor Pagination

The package supports the non-standard but documented "cursor pagination" profile.

Examples

The testing server implements a basic API server using the standard HTTP package.

Installation

Get the package using the go tool:

$ go get -u github.com/256dpi/jsonapi/v2

License

The MIT License (MIT)

Copyright (c) 2016 Joël Gähwiler

Documentation

Overview

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.

Index

Constants

View Source
const MediaType = "application/vnd.api+json"

MediaType is the official JSON API media type that should be used by all requests and responses.

View Source
const NullLink = "NULL"

NullLink can be used as a link to encode it as a null value.

Variables

This section is empty.

Functions

func WriteError

func WriteError(w http.ResponseWriter, err error) error

WriteError will write the passed error to the response writer.

Note: If the supplied error is not an Error a new InternalServerError is used instead. Does the passed Error have an invalid or zero status code it will be corrected to the Internal Server Error status code.

func WriteErrorList

func WriteErrorList(w http.ResponseWriter, errors ...*Error) error

WriteErrorList will write the passed errors to the response writer. The function will calculate a common status code for all the errors.

Does a passed Error have an invalid or zero status code it will be corrected to the Internal Server Error status code.

func WriteResource

func WriteResource(w http.ResponseWriter, status int, resource *Resource, links *DocumentLinks, included ...*Resource) error

WriteResource will wrap the passed resource, links and included resources in a document and write it to the passed response writer.

func WriteResources

func WriteResources(w http.ResponseWriter, status int, resources []*Resource, links *DocumentLinks, included ...*Resource) error

WriteResources will wrap the passed resources, links and included resources in a document and write it to the passed response writer.

func WriteResponse

func WriteResponse(w http.ResponseWriter, status int, doc *Document) error

WriteResponse will write the status and supplied document to the passed response writer.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a low-level jsonapi client.

func NewClient

func NewClient(config ClientConfig) *Client

NewClient will create and return a new client.

func NewClientWithClient

func NewClientWithClient(config ClientConfig, client *http.Client) *Client

NewClientWithClient will create and return a new client with the specified client.

func (*Client) Create

func (c *Client) Create(res *Resource) (*Document, error)

Create will create the specified resource.

func (*Client) Delete

func (c *Client) Delete(typ, id string) error

Delete will delete the specified resource.

func (*Client) Do

func (c *Client) Do(req Request, doc *Document) (*Document, error)

Do will perform the specified request and return the result.

func (*Client) Find

func (c *Client) Find(typ, id string, reqs ...Request) (*Document, error)

Find will find the specified resource. The additional requests are merged // with the base request.

func (*Client) List

func (c *Client) List(typ string, reqs ...Request) (*Document, error)

List will list the specified resources. The additional requests are merged with the base request.

func (*Client) Update

func (c *Client) Update(res *Resource) (*Document, error)

Update will update the specified resource.

type ClientConfig

type ClientConfig struct {
	BaseURI       string
	Authorizer    func(*http.Request)
	ResponseLimit int64
}

ClientConfig is used to configure a client.

type Document

type Document struct {
	// The documents primary data in the form of a single resource or a list
	// of resources.
	Data *HybridResource `json:"data,omitempty"`

	// A list of resources that are related to the primary data and/or other
	// included resources.
	Included []*Resource `json:"included,omitempty"`

	// A set of links related to the primary data.
	Links *DocumentLinks `json:"links,omitempty"`

	// A list of errors that occurred during the request.
	Errors []*Error `json:"errors,omitempty"`

	// Non-standard meta-information about the document.
	//
	// Note: Numbers are left as strings to avoid issues with mismatching types
	// when they are later assigned to a struct.
	Meta Map `json:"meta,omitempty"`
}

A Document is the root structure of every JSON API response. It is also used to include relationships.

See: http://jsonapi.org/format/#document-top-level.

func ParseDocument

func ParseDocument(r io.Reader) (*Document, error)

ParseDocument will decode a JSON API document from the passed reader.

Note: If the read document contains errors the first Error will be returned as an error.

type DocumentLinks struct {
	Self     Link `json:"self,omitempty"`
	Related  Link `json:"related,omitempty"`
	First    Link `json:"first,omitempty"`
	Previous Link `json:"prev,omitempty"`
	Next     Link `json:"next,omitempty"`
	Last     Link `json:"last,omitempty"`
}

DocumentLinks are a set of links related to a documents primary data.

See: http://jsonapi.org/format/#document-links.

type Error

type Error struct {
	// A unique identifier for this particular occurrence of the problem.
	ID string `json:"id,omitempty"`

	// Continuing links to other resources.
	Links *ErrorLinks `json:"links,omitempty"`

	// The HTTP status code applicable to this problem.
	Status int `json:"status,string,omitempty"`

	// An application-specific error code.
	Code string `json:"code,omitempty"`

	// A short, human-readable summary of the problem.
	Title string `json:"title,omitempty"`

	// A human-readable explanation specific to this occurrence of the problem.
	Detail string `json:"detail,omitempty"`

	// A parameter or pointer reference to the source of the error.
	Source *ErrorSource `json:"source,omitempty"`

	// Non-standard meta-information about the error.
	//
	// Note: Numbers are left as strings to avoid issues with mismatching types
	// when they are later assigned to a struct.
	Meta Map `json:"meta,omitempty"`
}

Error objects provide additional information about problems encountered while performing an operation.

See: http://jsonapi.org/format/#errors.

func BadRequest

func BadRequest(detail string) *Error

BadRequest returns a new bad request error.

func BadRequestParam

func BadRequestParam(detail, param string) *Error

BadRequestParam returns a new bad request error with a parameter source.

func BadRequestPointer

func BadRequestPointer(detail, pointer string) *Error

BadRequestPointer returns a new bad request error with a pointer source.

func ErrorFromStatus

func ErrorFromStatus(status int, detail string) *Error

ErrorFromStatus will return an error that has been derived from the passed status code.

Note: If the passed status code is not a valid HTTP status code, an Internal Server Error status code will be used instead.

func InternalServerError

func InternalServerError(detail string) *Error

InternalServerError returns na new internal server error.

func NotFound

func NotFound(detail string) *Error

NotFound returns a new not found error.

func (*Error) Error

func (e *Error) Error() string

Error returns a string representation of the error for logging purposes.

type ErrorLinks struct {
	// A link that leads to further details about this particular occurrence of
	// the problem.
	About string `json:"about"`
}

ErrorLinks contains continuing links to other resources.

See: http://jsonapi.org/format/#errors.

type ErrorSource

type ErrorSource struct {
	// A string indicating which URI query parameter caused the error.
	Parameter string `json:"parameter,omitempty"`

	// A JSON Pointer to the associated entity in the request document.
	Pointer string `json:"pointer,omitempty"`
}

ErrorSource contains a parameter or pointer reference to the source of the error.

See: http://jsonapi.org/format/#errors.

type HybridResource

type HybridResource struct {
	// A single resource.
	One *Resource

	// A list of resources.
	Many []*Resource
}

HybridResource is a transparent type that enables concrete marshalling and unmarshalling of a single resource value or a list of resources.

func (*HybridResource) MarshalJSON

func (r *HybridResource) MarshalJSON() ([]byte, error)

MarshalJSON will either encode a list or a single object.

func (*HybridResource) UnmarshalJSON

func (r *HybridResource) UnmarshalJSON(doc []byte) error

UnmarshalJSON detects if the passed JSON is a single object or a list.

type Intent

type Intent int

An Intent represents a valid combination of a request method and a URL pattern.

const (

	// ListResources is a variation of the following request:
	// GET /posts
	ListResources Intent

	// FindResource is a variation of the following request:
	// GET /posts/1
	FindResource

	// CreateResource is a variation of the following request:
	// POST /posts
	CreateResource

	// UpdateResource is a variation of the following request:
	// PATCH /posts/1
	UpdateResource

	// DeleteResource is a variation of the following request:
	// DELETE /posts/1
	DeleteResource

	// GetRelatedResources is a variation of the following requests:
	// GET /posts/1/author
	// GET /posts/1/comments
	GetRelatedResources

	// GetRelationship is a variation of the following requests:
	// GET /posts/1/relationships/author
	// GET /posts/1/relationships/comments
	GetRelationship

	// SetRelationship is a variation of the following requests:
	// PATCH /posts/1/relationships/author.
	// PATCH /posts/1/relationships/comments.
	SetRelationship

	// AppendToRelationship is a variation of the following request:
	// POST /posts/1/relationships/comments
	AppendToRelationship

	// RemoveFromRelationship is a variation of the following request:
	// DELETE /posts/1/relationships/comments
	RemoveFromRelationship

	// CollectionAction is a variation of the following requests:
	// GET /posts/top-titles
	// POST /posts/lock
	// PATCH /posts/settings
	// DELETE /posts/cache
	CollectionAction

	// ResourceAction is a variation of the following requests:
	// GET /posts/1/meta-data
	// POST /posts/1/publish
	// PATCH /posts/1/settings
	// DELETE /posts/1/history
	ResourceAction
)

func (Intent) DocumentExpected

func (i Intent) DocumentExpected() bool

DocumentExpected returns whether a request using this intent is expected to include a JSON API document.

Note: A response from an API may always include a document that at least contains one ore more errors.

func (Intent) RequestMethod

func (i Intent) RequestMethod() string

RequestMethod returns the matching HTTP request method for an Intent.

type Link string

Link is document link that also can be null by setting NullLink.

func (Link) MarshalJSON added in v2.1.0

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

MarshalJSON implements the json.Marshaler interface.

func (*Link) UnmarshalJSON added in v2.1.0

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

UnmarshalJSON implements the json.Unmarshaler interface.

type Map

type Map map[string]interface{}

Map is a general purpose map of string keys and arbitrary values.

Note: All methods in this package will leave numbers as strings to avoid issues with mismatching types when they are later assigned to a struct.

func StructToMap

func StructToMap(source interface{}, fields []string) (Map, error)

StructToMap will assign the fields of the source struct to a new map and additionally filter the map to only include the fields specified.

Note: The "json" tag will be respected to write proper field names. No filtering will be applied if fields is nil.

Note: Numbers are left as strings to avoid issues with mismatching types when they are later assigned to a struct again.

Warning: The function does actually convert the struct to json and then convert that json to a map. High performance applications might want to use a custom implementation that is much faster.

func (Map) Assign

func (m Map) Assign(target interface{}) error

Assign will assign the values in the map to the target struct.

Note: The "json" tag will be respected to match field names.

Warning: The function does actually convert the map to json and then assign that json to the struct. High performance applications might want to use a custom implementation that is much faster.

type Parser

type Parser struct {
	// Prefix is the expected prefix of the endpoint.
	Prefix string

	// A list of valid collection actions and the allowed methods.
	//
	// Note: Make sure the actions do not conflict with the resource id format.
	CollectionActions map[string][]string

	// A list of valid resource actions and the allowed methods.
	//
	// Note: Make sure the actions do not contain "relationships" or use
	// related resource types.
	ResourceActions map[string][]string
}

A Parser is used to parse incoming requests.

func (*Parser) ParseRequest

func (p *Parser) ParseRequest(r *http.Request) (*Request, error)

ParseRequest will parse the passed request and return a new Request with the parsed data. It will return an error if the content type, request method or url is invalid. Any returned error can directly be written using WriteError.

type Request

type Request struct {
	// The parsed JSON API intent of the request.
	Intent Intent

	// The prefix of the endpoint e.g. "api". It should not contain any prefix
	// or suffix slashes.
	Prefix string

	// The fragments parsed from the URL of the request. The fragments should not
	// contain any prefix or suffix slashes.
	ResourceType     string
	ResourceID       string
	RelatedResource  string
	Relationship     string
	CollectionAction string
	ResourceAction   string

	// The requested resources to be included in the response. This is read
	// from the "include" query parameter.
	Include []string

	// The pagination details of the request. Zero values mean no pagination
	// details have been provided. These values are read from the "page[number]",
	// "page[size]", "page[offset]", "page[limit]", "page[before]" and
	// "page[after]" query parameters. These parameters do not belong to the
	// standard, but are recommended.
	PageNumber int64
	PageSize   int64
	PageOffset int64
	PageLimit  int64
	PageBefore string
	PageAfter  string

	// The pagination type that has been requested. This is read from the
	// "pagination" query parameter. Possible values are "offset" or "cursor.
	// This parameter does not belong to the standard.
	Pagination string

	// The sorting that has been requested. This is read from the "sort" query
	// parameter.
	Sorting []string

	// The sparse fields that have been requested. This is read from the "fields"
	// query parameter.
	Fields map[string][]string

	// The filtering that has been requested. This is read from the "filter"
	// query parameter. This parameter does not belong to the standard, but is
	// recommended.
	Filters map[string][]string

	// The search query that has been requested. This is read from the "search"
	// query parameter. This parameter does not belong to the standard.
	Search string
}

A Request contains all JSON API related information parsed from a low level request.

func ParseRequest

func ParseRequest(r *http.Request, prefix string) (*Request, error)

ParseRequest is a short-hand for Parser.ParseRequest and will be removed in future releases.

func (*Request) Base

func (r *Request) Base() string

Base will generate the base path for this request, which includes the type and id if present.

func (Request) Merge added in v2.1.0

func (r Request) Merge(reqs ...Request) Request

Merge will merge the provided requests with the receiver and return a new request.

func (*Request) Path added in v2.1.0

func (r *Request) Path() string

Path will generate the path for this request, which includes all path elements if available.

func (*Request) Query

func (r *Request) Query() url.Values

Query will collect and return all query parameters from the request.

func (*Request) Self

func (r *Request) Self() string

Self will generate the "self" URL for this request, which includes all path elements and query parameters if available.

type Resource

type Resource struct {
	// The mandatory type of the resource.
	Type string `json:"type"`

	// The mandatory id of the resource.
	//
	// Exception: The id is not required when the resource object
	// originates at the client and represents a new resource to be created on
	// the server.
	ID string `json:"id,omitempty"`

	// An attributes map representing some of the resource's data.
	//
	// Note: Numbers are left as strings to avoid issues with mismatching types
	// when they are later assigned to a struct.
	Attributes Map `json:"attributes,omitempty"`

	// A relationships object describing relationships between the resource and
	// other JSON API resources.
	Relationships map[string]*Document `json:"relationships,omitempty"`

	// Non-standard meta-information about the resource.
	//
	// Note: Numbers are left as strings to avoid issues with mismatching types
	// when they are later assigned to a struct.
	Meta Map `json:"meta,omitempty"`
}

A Resource is carried by a document and provides the basic structure for JSON API resource objects and resource identifier objects.

See: http://jsonapi.org/format/#document-resource-objects and http://jsonapi.org/format/#document-resource-identifier-objects.

type Server

type Server struct {
	Config  ServerConfig
	Parser  *Parser
	Data    map[string]map[string]*Resource
	Counter int
	Mutex   sync.Mutex
}

Server implements a basic in-memory jsonapi resource server intended for testing purposes.

func NewServer

func NewServer(config ServerConfig) *Server

NewServer will create and return a new server.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements the http.Handler interface.

type ServerConfig

type ServerConfig struct {
	Prefix string
	Types  []string
}

ServerConfig is used to configure a server.

Jump to

Keyboard shortcuts

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