jsonapi

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 19 Imported by: 0

README

jsonapi

CI CodeQL Coverage Mutation Documentation Go Reference Release Go License

jsonapi is a strict, framework-agnostic implementation of JSON:API 1.1, the official Atomic Operations extension, the official Cursor Pagination profile, and the published JSON:API recommendations.

Status

The package has a stable v1 API. Its supported protocol surface is conformance-tested and production code is held to meaningful 100% statement coverage. Read the compatibility policy before adopting a revision.

Requirements

  • Go 1.26.6 or later

Installation

go get github.com/faustbrian/go-jsonapi

Quickstart

document := jsonapi.Document{Data: jsonapi.ResourceData(
    jsonapi.ResourceObject{
        Type: "articles",
        ID:   "1",
        Attributes: jsonapi.Attributes{
            "title": "JSON:API in Go",
        },
    },
)}

payload, err := jsonapi.Marshal(document)
if err != nil {
    return err
}

Decode untrusted input with Unmarshal or a configured Codec. Use request-specific validation contexts, bounded decoding, content negotiation, and query parsing as described in the quickstart.

Package Guarantees

  • JSON:API 1.1 document modeling, strict decoding, validation, and stable serialization
  • compound documents, relationships, errors, local identifiers, and contextual request/response validation
  • sparse fieldsets, includes, sorting, pagination, filtering, and registered query families
  • media-type negotiation with extensions, profiles, quality values, and wildcard candidates
  • full official Atomic Operations and Cursor Pagination support
  • registered extension members, profile validators, UTF-8 enforcement, and configurable resource limits

The package does not choose an HTTP router, persistence layer, filtering language, cursor encoding, authentication policy, or domain-error mapping.

Documentation

Start with the documentation index, quickstart, adoption guide, and API reference. The conformance matrix, extensions and profiles, recommendations, specification decision register, and hardening evidence define the supported protocol surface.

AI tools can use llms.txt and llms-full.txt. Release history is maintained in CHANGELOG.md.

Development

Run make check before submitting a change. This enforces formatting, static analysis, race tests, meaningful 100% coverage, fuzz smoke, benchmarks, documentation, and vulnerability scanning.

Contributing

Read CONTRIBUTING.md and follow the code of conduct. Normative requirements, recommendations, extensions, profiles, and application conventions are reviewed as separate categories.

Security

Report vulnerabilities privately according to SECURITY.md. Review the security guide and threat model before processing untrusted input.

License

jsonapi is available under the MIT License. Attribution and third-party policy are recorded in NOTICE and THIRD_PARTY_NOTICES.md.

Ecosystem

Use the Golib documentation portal to choose companion packages, supported stacks, recipes, and operations guidance.

Documentation

Overview

Package jsonapi provides explicit types for building and validating JSON:API 1.1 documents.

Index

Examples

Constants

View Source
const (
	// CursorUnsupportedSortTypeURI identifies an unsupported sort error.
	CursorUnsupportedSortTypeURI = "https://jsonapi.org/profiles/ethanresnick/cursor-pagination/unsupported-sort"
	// CursorMaxSizeExceededTypeURI identifies a maximum page size error.
	CursorMaxSizeExceededTypeURI = "https://jsonapi.org/profiles/ethanresnick/cursor-pagination/max-size-exceeded"
	// CursorRangeNotSupportedTypeURI identifies a rejected range request.
	CursorRangeNotSupportedTypeURI = "https://jsonapi.org/profiles/ethanresnick/cursor-pagination/range-pagination-not-supported"
)
View Source
const (
	// DefaultMaxDocumentBytes bounds one encoded JSON:API document at 16 MiB.
	DefaultMaxDocumentBytes = 16 << 20
	// DefaultMaxNestingDepth bounds nested JSON arrays and objects.
	DefaultMaxNestingDepth = 64
	// DefaultMaxObjectMembers bounds members in any one JSON object.
	DefaultMaxObjectMembers = 10_000
	// DefaultMaxArrayItems bounds items in any one JSON array.
	DefaultMaxArrayItems = 100_000
	// DefaultMaxTotalValues bounds total JSON values visited during decoding.
	DefaultMaxTotalValues = 1_000_000
	// DefaultMaxQueryParameters bounds distinct decoded query names.
	DefaultMaxQueryParameters = 100
	// DefaultMaxQueryValues bounds decoded query values across all names.
	DefaultMaxQueryValues = 200
	// DefaultMaxQueryNameBytes bounds one decoded query parameter name.
	DefaultMaxQueryNameBytes = 1_024
	// DefaultMaxQueryValueBytes bounds one decoded query parameter value.
	DefaultMaxQueryValueBytes = 8_192
	// DefaultMaxQueryTotalBytes bounds decoded names and values in aggregate.
	DefaultMaxQueryTotalBytes = 64 << 10
	// DefaultMaxQuerySelectors bounds bracket selectors in one name.
	DefaultMaxQuerySelectors = 32
	// DefaultMaxQueryListItems bounds include, fields, or sort list entries.
	DefaultMaxQueryListItems = 1_000
	// DefaultMaxNegotiationHeaderBytes bounds one media type header value.
	DefaultMaxNegotiationHeaderBytes = 32 << 10
	// DefaultMaxAcceptCandidates bounds comma-separated Accept candidates.
	DefaultMaxAcceptCandidates = 100
	// DefaultMaxParameterURIs bounds URIs in one ext or profile parameter.
	DefaultMaxParameterURIs = 100
	// DefaultMaxNegotiationURIBytes bounds one extension or profile URI.
	DefaultMaxNegotiationURIBytes = 2_048
	// DefaultMaxSupportedURIs bounds configured extensions and profiles.
	DefaultMaxSupportedURIs = 1_000
)
View Source
const AtomicExtensionURI = "https://jsonapi.org/ext/atomic"

AtomicExtensionURI identifies the official Atomic Operations extension.

View Source
const CursorPaginationProfileURI = "http://jsonapi.org/profiles/ethanresnick/cursor-pagination/"

CursorPaginationProfileURI identifies the official Cursor Pagination profile. The profile normatively uses this HTTP URI.

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

MediaTypeJSONAPI is the registered JSON:API media type.

Variables

This section is empty.

Functions

func Marshal

func Marshal(document Document) ([]byte, error)

Marshal validates and deterministically encodes a JSON:API document.

Example
package main

import (
	"fmt"

	jsonapi "github.com/faustbrian/go-jsonapi"
)

func main() {
	document := jsonapi.Document{Data: jsonapi.ResourceData(
		jsonapi.ResourceObject{
			Type:       "articles",
			ID:         "1",
			Attributes: jsonapi.Attributes{"title": "JSON:API in Go"},
		},
	)}

	payload, err := jsonapi.Marshal(document)
	fmt.Println(string(payload))
	fmt.Println(err)
}
Output:
{"data":{"type":"articles","id":"1","attributes":{"title":"JSON:API in Go"}}}
<nil>

func MarshalAtomic

func MarshalAtomic(document AtomicDocument) ([]byte, error)

MarshalAtomic validates and deterministically encodes an Atomic Operations document.

Example
package main

import (
	"fmt"

	jsonapi "github.com/faustbrian/go-jsonapi"
)

func main() {
	document := jsonapi.AtomicDocument{Operations: []jsonapi.AtomicOperation{{
		Op:   jsonapi.AtomicRemove,
		Href: "/articles/1",
	}}}

	payload, err := jsonapi.MarshalAtomic(document)
	fmt.Println(string(payload))
	fmt.Println(err)
}
Output:
{"atomic:operations":[{"op":"remove","href":"/articles/1"}]}
<nil>

func MarshalAtomicWith

func MarshalAtomicWith(
	document AtomicDocument,
	options AtomicValidationOptions,
) ([]byte, error)

MarshalAtomicWith validates in the supplied Atomic protocol context and deterministically encodes a document.

func MarshalWith

func MarshalWith(document Document, options ValidationOptions) ([]byte, error)

MarshalWith validates in the supplied protocol context and deterministically encodes a JSON:API document.

func ParseCursorItemMeta

func ParseCursorItemMeta(meta Meta) (string, bool, error)

ParseCursorItemMeta validates and extracts an item cursor. The boolean reports whether the cursor member was present.

func ParseCursorItemMetaAs

func ParseCursorItemMetaAs(meta Meta, member string) (string, bool, error)

ParseCursorItemMetaAs validates and extracts an item cursor using a profile element alias. An empty member uses the default page name.

func ValidateCursorPaginationLinks(links Links) error

ValidateCursorPaginationLinks enforces the profile requirement that every paginated data instance contains both prev and next links.

Types

type AtomicDocument

type AtomicDocument struct {
	JSONAPI    *JSONAPI
	Links      Links
	Operations []AtomicOperation
	Results    []AtomicResult
	Errors     []ErrorObject
	Meta       Meta
}

AtomicDocument is a document using the official Atomic Operations extension. Operations, results, errors, and meta retain nil-versus-empty presence semantics.

func ExecuteAtomic

func ExecuteAtomic(
	ctx context.Context,
	beginner AtomicTransactionBeginner,
	document AtomicDocument,
) (AtomicDocument, error)

ExecuteAtomic validates an Atomic request, applies operations in document order, and commits only after every operation succeeds. Any failure after a transaction begins triggers exactly one rollback attempt.

func UnmarshalAtomic

func UnmarshalAtomic(payload []byte) (AtomicDocument, error)

UnmarshalAtomic strictly decodes and validates an Atomic Operations document.

func UnmarshalAtomicWith

func UnmarshalAtomicWith(
	payload []byte,
	options AtomicValidationOptions,
) (AtomicDocument, error)

UnmarshalAtomicWith strictly decodes and validates a document in the supplied Atomic protocol context.

func UnmarshalAtomicWithLimits

func UnmarshalAtomicWithLimits(
	payload []byte,
	options AtomicValidationOptions,
	limits DecodeLimits,
) (AtomicDocument, error)

UnmarshalAtomicWithLimits strictly decodes and validates an Atomic document with explicit resource limits. Zero limit fields use production defaults.

func (AtomicDocument) MarshalJSON

func (document AtomicDocument) MarshalJSON() ([]byte, error)

MarshalJSON preserves explicitly empty Atomic Operations members.

func (AtomicDocument) Validate

func (document AtomicDocument) Validate() error

Validate checks Atomic Operations document and operation invariants.

func (AtomicDocument) ValidateWith

func (document AtomicDocument) ValidateWith(options AtomicValidationOptions) error

ValidateWith checks an Atomic document in a request or response context.

type AtomicExecutionError

type AtomicExecutionError struct {
	Phase          string
	OperationIndex int
	Cause          error
	RollbackCause  error
}

AtomicExecutionError identifies the failed transaction phase and operation. OperationIndex is -1 for begin and commit failures.

func (*AtomicExecutionError) Error

func (err *AtomicExecutionError) Error() string

Error implements error.

func (*AtomicExecutionError) Unwrap

func (err *AtomicExecutionError) Unwrap() []error

Unwrap exposes both the primary and rollback failures to errors.Is/As.

type AtomicOperation

type AtomicOperation struct {
	Op   AtomicOperationCode
	Ref  *AtomicReference
	Href string
	Data *PrimaryData
	Meta Meta
	// contains filtered or unexported fields
}

AtomicOperation describes one ordered mutation in an atomic request.

func (AtomicOperation) MarshalJSON

func (operation AtomicOperation) MarshalJSON() ([]byte, error)

MarshalJSON preserves an explicitly empty operation meta object.

func (AtomicOperation) WithHref

func (operation AtomicOperation) WithHref(value string) AtomicOperation

WithHref returns a copy whose href member is present, including when value is the empty URI-reference.

type AtomicOperationCode

type AtomicOperationCode string

AtomicOperationCode identifies an Atomic Operations mutation.

const (
	// AtomicAdd creates a resource or adds relationship members.
	AtomicAdd AtomicOperationCode = "add"
	// AtomicUpdate updates a resource or replaces relationship linkage.
	AtomicUpdate AtomicOperationCode = "update"
	// AtomicRemove removes a resource or relationship members.
	AtomicRemove AtomicOperationCode = "remove"
)

type AtomicPanicError

type AtomicPanicError struct {
	Phase string
	Value any
}

AtomicPanicError identifies a panic raised by an application transaction callback. Value is retained for explicit diagnostics but omitted from Error.

func (*AtomicPanicError) Error

func (err *AtomicPanicError) Error() string

Error implements error without formatting the potentially sensitive panic value.

func (*AtomicPanicError) Unwrap

func (err *AtomicPanicError) Unwrap() error

Unwrap exposes a panic value that is itself an error.

type AtomicReference

type AtomicReference struct {
	Type         string `json:"type"`
	ID           string `json:"id,omitempty"`
	LID          string `json:"lid,omitempty"`
	Relationship string `json:"relationship,omitempty"`
	// contains filtered or unexported fields
}

AtomicReference identifies a resource or one of its relationships.

func (AtomicReference) MarshalJSON

func (reference AtomicReference) MarshalJSON() ([]byte, error)

MarshalJSON preserves explicitly empty reference identity members.

func (AtomicReference) WithID

func (reference AtomicReference) WithID(value string) AtomicReference

WithID returns a copy whose id member is present, including when value is the empty string.

func (AtomicReference) WithLID

func (reference AtomicReference) WithLID(value string) AtomicReference

WithLID returns a copy whose lid member is present, including when value is the empty string.

func (AtomicReference) WithRelationship

func (reference AtomicReference) WithRelationship(value string) AtomicReference

WithRelationship returns a copy whose relationship member is present.

type AtomicResult

type AtomicResult struct {
	Data *PrimaryData
	Meta Meta
}

AtomicResult describes the result at the same position as its operation.

func (AtomicResult) MarshalJSON

func (result AtomicResult) MarshalJSON() ([]byte, error)

MarshalJSON preserves an explicitly empty result meta object.

type AtomicTransaction

type AtomicTransaction interface {
	ApplyAtomic(context.Context, AtomicOperation) (AtomicResult, error)
	CommitAtomic(context.Context) error
	RollbackAtomic(context.Context) error
}

AtomicTransaction applies operations within one application-owned transaction. Implementations must not commit from ApplyAtomic.

type AtomicTransactionBeginner

type AtomicTransactionBeginner interface {
	BeginAtomic(context.Context) (AtomicTransaction, error)
}

AtomicTransactionBeginner starts an application-owned transaction.

type AtomicValidationContext

type AtomicValidationContext uint8

AtomicValidationContext identifies an Atomic Operations protocol boundary.

const (
	// AtomicGenericContext applies context-independent Atomic document rules.
	AtomicGenericContext AtomicValidationContext = iota
	// AtomicRequestContext requires an operations request document.
	AtomicRequestContext
	// AtomicResponseContext requires a valid results or errors response.
	AtomicResponseContext
)

type AtomicValidationOptions

type AtomicValidationOptions struct {
	Context             AtomicValidationContext
	ExpectedResultCount int
	ExpectedOperations  []AtomicOperation
}

AtomicValidationOptions configures request or response validation.

type Attributes

type Attributes map[string]any

Attributes contains the non-relationship fields of a resource object.

type CallbackError

type CallbackError struct {
	Phase      string
	Cause      error
	PanicValue any
	// contains filtered or unexported fields
}

CallbackError contains a failure from an application-supplied validator. Error deliberately omits the callback's error or panic value. Cause and PanicValue remain available for explicit diagnostics.

func (*CallbackError) CallbackPanicValue

func (err *CallbackError) CallbackPanicValue() (any, bool)

CallbackPanicValue returns the panic value and whether the callback panicked.

func (*CallbackError) CallbackPhase

func (err *CallbackError) CallbackPhase() string

CallbackPhase identifies the callback seam that failed.

func (*CallbackError) Error

func (err *CallbackError) Error() string

Error implements error without disclosing application-owned values.

func (*CallbackError) Unwrap

func (err *CallbackError) Unwrap() error

Unwrap exposes an error returned by or panicked from the callback.

type Codec

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

Codec is a strict document codec with explicitly registered extension members.

func NewCodec

func NewCodec(options CodecOptions) (*Codec, error)

NewCodec validates all extension definitions before constructing a codec.

func (*Codec) Marshal

func (codec *Codec) Marshal(document Document) ([]byte, error)

Marshal validates and deterministically encodes a registered document.

func (*Codec) Unmarshal

func (codec *Codec) Unmarshal(payload []byte) (Document, error)

Unmarshal strictly decodes registered extension members and the core document.

type CodecOptions

type CodecOptions struct {
	Extensions []ExtensionDefinition
	Profiles   []ProfileDefinition
	Validation ValidationOptions
	Limits     DecodeLimits
}

CodecOptions configures applied extensions and core validation context.

type CursorEstimatedTotal

type CursorEstimatedTotal struct {
	BestGuess *int64
}

CursorEstimatedTotal describes an optional estimate of collection size.

type CursorPage

type CursorPage struct {
	Request     CursorPageRequest
	Links       Links
	Meta        Meta
	Items       []Meta
	HasMore     bool
	HasPrevious bool
	HasNext     bool
}

CursorPage supplies the evidence needed to validate one paginated data instance without coupling pagination to a storage implementation.

func (CursorPage) Validate

func (page CursorPage) Validate() error

Validate checks a top-level paginated data instance.

func (CursorPage) ValidateAt

func (page CursorPage) ValidateAt(path string) error

ValidateAt checks paginated data at a top-level or relationship object path. The supplied path identifies the object containing links, meta, and data.

type CursorPageMeta

type CursorPageMeta struct {
	RangeTruncated *bool
	Total          *int64
	EstimatedTotal *CursorEstimatedTotal
}

CursorPageMeta describes metadata adjacent to paginated data.

func ParseCursorPageMeta

func ParseCursorPageMeta(meta Meta) (CursorPageMeta, bool, error)

ParseCursorPageMeta validates and extracts pagination metadata. The boolean reports whether the page member was present.

func ParseCursorPageMetaAs

func ParseCursorPageMetaAs(meta Meta, member string) (CursorPageMeta, bool, error)

ParseCursorPageMetaAs validates and extracts pagination metadata using a profile element alias. An empty member uses the default page name.

func (CursorPageMeta) Meta

func (metadata CursorPageMeta) Meta() (Meta, error)

Meta validates and wraps pagination metadata in the profile's page member.

func (CursorPageMeta) MetaAs

func (metadata CursorPageMeta) MetaAs(member string) (Meta, error)

MetaAs validates and wraps pagination metadata using a profile element alias. An empty member uses the profile's default page name.

type CursorPageRequest

type CursorPageRequest struct {
	Size          int
	SizePresent   bool
	After         string
	AfterPresent  bool
	Before        string
	BeforePresent bool
	Range         bool
	PageMember    string
}

CursorPageRequest is the validated cursor pagination request for an endpoint.

type CursorPagination

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

CursorPagination parses the page family for one configured endpoint.

Example
package main

import (
	"fmt"

	jsonapi "github.com/faustbrian/go-jsonapi"
)

func main() {
	pagination, err := jsonapi.NewCursorPagination(jsonapi.CursorPaginationConfig{
		DefaultSize: 20,
		MaxSize:     100,
		AllowRange:  true,
	})
	if err != nil {
		fmt.Println(err)
		return
	}

	request, err := pagination.Parse(jsonapi.ParameterFamily{
		"page[size]":  {"25"},
		"page[after]": {"opaque-cursor"},
	})
	fmt.Println(request.Size, request.After, request.Range)
	fmt.Println(err)
}
Output:
25 opaque-cursor false
<nil>

func NewCursorPagination

func NewCursorPagination(config CursorPaginationConfig) (*CursorPagination, error)

NewCursorPagination validates endpoint policy before it serves requests. A MaxSize of zero means unbounded ordinary pagination; range pagination requires a finite maximum because that maximum becomes its default size.

func (*CursorPagination) Parse

func (pagination *CursorPagination) Parse(family ParameterFamily) (CursorPageRequest, error)

Parse validates the page parameter family according to the profile and endpoint configuration.

func (*CursorPagination) ParseQuery

func (pagination *CursorPagination) ParseQuery(query Query) (CursorPageRequest, error)

ParseQuery validates both the page family and the endpoint's stable sorting requirement. When ValidateSort is nil, the caller remains responsible for applying a unique order before fetching the page.

type CursorPaginationConfig

type CursorPaginationConfig struct {
	DefaultSize    int
	MaxSize        int
	AllowRange     bool
	PageMember     string
	ValidateCursor func(string) error
	ValidateSort   func([]SortField) error
}

CursorPaginationConfig defines endpoint-specific page sizing, range support, and opaque cursor validation.

type CursorPaginationError

type CursorPaginationError struct {
	Status     int
	Parameter  string
	Code       string
	Message    string
	MaxSize    int
	PageMember string
	Cause      error
}

CursorPaginationError describes a profile query failure and its required HTTP status.

func (*CursorPaginationError) Error

func (err *CursorPaginationError) Error() string

Error implements error.

func (*CursorPaginationError) ErrorObject

func (err *CursorPaginationError) ErrorObject(title, detail string) ErrorObject

ErrorObject converts a profile failure to a JSON:API error object with the required source, type link, and profile metadata.

func (*CursorPaginationError) Unwrap

func (err *CursorPaginationError) Unwrap() error

Unwrap returns an application cursor or sort validator failure without including its potentially sensitive text in Error.

type DecodeError

type DecodeError struct {
	Path    string
	Code    string
	Message string
	Cause   error
}

DecodeError identifies a malformed JSON representation by JSON Pointer.

func (*DecodeError) Error

func (err *DecodeError) Error() string

Error implements error.

func (*DecodeError) Unwrap

func (err *DecodeError) Unwrap() error

Unwrap returns the underlying JSON decoding error, when present.

type DecodeLimits

type DecodeLimits struct {
	MaxDocumentBytes int
	MaxNestingDepth  int
	MaxObjectMembers int
	MaxArrayItems    int
	MaxTotalValues   int
}

DecodeLimits bounds resource use before semantic document decoding. Zero fields use the production defaults; negative fields are invalid.

func DefaultDecodeLimits

func DefaultDecodeLimits() DecodeLimits

DefaultDecodeLimits returns the package's bounded production defaults.

type Document

type Document struct {
	JSONAPI           *JSONAPI         `json:"jsonapi,omitempty"`
	Links             Links            `json:"links,omitempty"`
	Data              *PrimaryData     `json:"data,omitempty"`
	Included          []ResourceObject `json:"included,omitempty"`
	Errors            []ErrorObject    `json:"errors,omitempty"`
	Meta              Meta             `json:"meta,omitempty"`
	AdditionalMembers Members          `json:"-"`
}

Document is a top-level JSON:API document.

Data is a pointer so callers can distinguish an absent data member from a data member whose value is null.

func Unmarshal

func Unmarshal(payload []byte) (Document, error)

Unmarshal strictly decodes and validates a JSON:API document.

func UnmarshalWith

func UnmarshalWith(payload []byte, options ValidationOptions) (Document, error)

UnmarshalWith strictly decodes and validates a JSON:API document in the supplied protocol context.

func UnmarshalWithLimits

func UnmarshalWithLimits(
	payload []byte,
	options ValidationOptions,
	limits DecodeLimits,
) (Document, error)

UnmarshalWithLimits strictly decodes and validates a JSON:API document with explicit resource limits. Zero limit fields use production defaults.

func (Document) MarshalJSON

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

MarshalJSON implements json.Marshaler while preserving explicitly empty top-level arrays and objects.

func (Document) Validate

func (document Document) Validate() error

Validate checks the context-independent structural requirements of a JSON:API document and returns all violations in document order.

func (Document) ValidateWith

func (document Document) ValidateWith(options ValidationOptions) error

ValidateWith checks a document using rules for a specific request or response boundary.

type ErrorObject

type ErrorObject struct {
	ID                string       `json:"id,omitempty"`
	Links             Links        `json:"links,omitempty"`
	Status            string       `json:"status,omitempty"`
	Code              string       `json:"code,omitempty"`
	Title             string       `json:"title,omitempty"`
	Detail            string       `json:"detail,omitempty"`
	Source            *ErrorSource `json:"source,omitempty"`
	Meta              Meta         `json:"meta,omitempty"`
	AdditionalMembers Members      `json:"-"`
	// contains filtered or unexported fields
}

ErrorObject describes one JSON:API error.

func (ErrorObject) MarshalJSON

func (apiError ErrorObject) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler while preserving explicitly empty error links and meta objects.

func (ErrorObject) WithCode

func (apiError ErrorObject) WithCode(value string) ErrorObject

WithCode returns a copy whose code member is present.

func (ErrorObject) WithDetail

func (apiError ErrorObject) WithDetail(value string) ErrorObject

WithDetail returns a copy whose detail member is present.

func (ErrorObject) WithID

func (apiError ErrorObject) WithID(value string) ErrorObject

WithID returns a copy whose id member is present.

func (ErrorObject) WithStatus

func (apiError ErrorObject) WithStatus(value string) ErrorObject

WithStatus returns a copy whose status member is present.

func (ErrorObject) WithTitle

func (apiError ErrorObject) WithTitle(value string) ErrorObject

WithTitle returns a copy whose title member is present.

type ErrorSource

type ErrorSource struct {
	Pointer           string  `json:"pointer,omitempty"`
	Parameter         string  `json:"parameter,omitempty"`
	Header            string  `json:"header,omitempty"`
	AdditionalMembers Members `json:"-"`
	// contains filtered or unexported fields
}

ErrorSource identifies the source of an error in a request.

func (ErrorSource) MarshalJSON

func (source ErrorSource) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler for registered extension members.

func (ErrorSource) WithHeader

func (source ErrorSource) WithHeader(value string) ErrorSource

WithHeader returns a copy whose header member is present.

func (ErrorSource) WithParameter

func (source ErrorSource) WithParameter(value string) ErrorSource

WithParameter returns a copy whose parameter member is present.

func (ErrorSource) WithPointer

func (source ErrorSource) WithPointer(value string) ErrorSource

WithPointer returns a copy whose pointer member is present.

type ExtensionDefinition

type ExtensionDefinition struct {
	URI       string
	Namespace string
	Members   []MemberDefinition
}

ExtensionDefinition declares an applied JSON:API extension.

type Identifier

type Identifier struct {
	Type              string  `json:"type"`
	ID                string  `json:"id,omitempty"`
	LID               string  `json:"lid,omitempty"`
	Meta              Meta    `json:"meta,omitempty"`
	AdditionalMembers Members `json:"-"`
	// contains filtered or unexported fields
}

Identifier identifies a resource by type and either server or local ID.

func (Identifier) MarshalJSON

func (identifier Identifier) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler while preserving an explicitly empty identifier meta object.

func (Identifier) WithID

func (identifier Identifier) WithID(value string) Identifier

WithID returns a copy whose id member is present, including when value is the empty string.

func (Identifier) WithLID

func (identifier Identifier) WithLID(value string) Identifier

WithLID returns a copy whose lid member is present, including when value is the empty string.

type JSONAPI

type JSONAPI struct {
	Version           string   `json:"version,omitempty"`
	Ext               []string `json:"ext,omitempty"`
	Profile           []string `json:"profile,omitempty"`
	Meta              Meta     `json:"meta,omitempty"`
	AdditionalMembers Members  `json:"-"`
	// contains filtered or unexported fields
}

JSONAPI describes the JSON:API implementation and applied extensions and profiles.

func (JSONAPI) MarshalJSON

func (object JSONAPI) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler while preserving explicitly empty extension, profile, and meta members.

func (JSONAPI) WithVersion

func (object JSONAPI) WithVersion(value string) JSONAPI

WithVersion returns a copy whose version member is present, including when value is the empty string.

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

Link is a string, object, null, or registered extension-defined links-object member value. Construct values with URI, ObjectLink, NullLink, or ExtensionLinkValue.

func ExtensionLinkValue

func ExtensionLinkValue(value any) Link

ExtensionLinkValue returns an opaque value for a member defined by an extension in a JSON:API links object. A Codec must register that member at LinksObjectMemberScope before the value can be marshaled.

func LinkFromObject

func LinkFromObject(object LinkObject) Link

LinkFromObject returns a link represented by a JSON:API 1.1 link object.

func NullLink() Link

NullLink returns a null link.

func ObjectLink(href string, meta Meta) Link

ObjectLink returns a link object with an href and optional meta object.

func URI

func URI(href string) Link

URI returns a link represented by a URI string.

func (Link) ExtensionValue

func (link Link) ExtensionValue() (any, bool)

ExtensionValue returns the opaque extension-defined links-object member value and whether this Link represents one.

func (Link) MarshalJSON

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

MarshalJSON implements json.Marshaler.

func (Link) WithRel

func (link Link) WithRel(value string) Link

WithRel returns a copy whose rel member is present, including when value is the empty string.

func (Link) WithTitle

func (link Link) WithTitle(value string) Link

WithTitle returns a copy whose title member is present, including when value is the empty string.

func (Link) WithType

func (link Link) WithType(value string) Link

WithType returns a copy whose type member is present, including when value is the empty string.

type LinkHreflang

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

LinkHreflang represents the scalar or array form of a link object's hreflang member. Construct values with LanguageTag or LanguageTags.

func LanguageTag

func LanguageTag(tag string) *LinkHreflang

LanguageTag returns the scalar form of a link object's hreflang member.

func LanguageTags

func LanguageTags(tags ...string) *LinkHreflang

LanguageTags returns the array form of a link object's hreflang member.

type LinkObject

type LinkObject struct {
	Href              string
	Rel               string
	DescribedBy       *Link
	Title             string
	Type              string
	Hreflang          *LinkHreflang
	Meta              Meta
	AdditionalMembers Members
}

LinkObject contains every member supported by a JSON:API 1.1 link object.

type Links map[string]Link

Links maps link relation names to links.

type MediaType

type MediaType struct {
	Extensions []string
	Profiles   []string
}

MediaType describes extensions and profiles applied to a JSON:API payload.

func (MediaType) String

func (mediaType MediaType) String() string

String returns the canonical JSON:API Content-Type value.

type MemberDefinition

type MemberDefinition struct {
	Scope    MemberScope
	Name     string
	Validate func(any) error
}

MemberDefinition declares one extension member and its optional value validator.

type MemberScope

type MemberScope uint8

MemberScope identifies the JSON:API object where a custom member is valid.

const (
	// TopLevelMemberScope registers a top-level document member.
	TopLevelMemberScope MemberScope = iota + 1
	// ResourceMemberScope registers a resource object member.
	ResourceMemberScope
	// RelationshipMemberScope registers a relationship object member.
	RelationshipMemberScope
	// IdentifierMemberScope registers a resource identifier member.
	IdentifierMemberScope
	// JSONAPIMemberScope registers a JSON:API object member.
	JSONAPIMemberScope
	// ErrorMemberScope registers an error object member.
	ErrorMemberScope
	// ErrorSourceMemberScope registers an error source object member.
	ErrorSourceMemberScope
	// LinksObjectMemberScope registers a member of a links object.
	LinksObjectMemberScope
	// LinkObjectMemberScope registers a link object member.
	LinkObjectMemberScope
)

type Members

type Members map[string]any

Members contains registered extension or profile members attached to a JSON:API-defined object.

type Meta

type Meta map[string]any

Meta contains non-standard information associated with a JSON:API object.

func CursorItemMeta

func CursorItemMeta(cursor string) Meta

CursorItemMeta wraps an opaque item cursor in profile metadata.

func CursorItemMetaAs

func CursorItemMetaAs(member, cursor string) (Meta, error)

CursorItemMetaAs wraps an item cursor using a profile element alias. An empty member uses the default page name.

type NegotiatedMedia

type NegotiatedMedia struct {
	MediaType   MediaType
	ContentType string
	VaryAccept  bool
}

NegotiatedMedia is the representation selected for an Accept header.

type NegotiationError

type NegotiationError struct {
	Status  int
	Code    string
	Message string
}

NegotiationError describes an HTTP content-negotiation failure without coupling the package to a particular HTTP framework.

func (*NegotiationError) Error

func (err *NegotiationError) Error() string

Error implements error.

type NegotiationLimits

type NegotiationLimits struct {
	MaxHeaderBytes      int
	MaxAcceptCandidates int
	MaxParameterURIs    int
	MaxURIBytes         int
	MaxSupportedURIs    int
}

NegotiationLimits bounds media type configuration and header processing.

func DefaultNegotiationLimits

func DefaultNegotiationLimits() NegotiationLimits

DefaultNegotiationLimits returns bounded media type defaults.

type Negotiator

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

Negotiator validates JSON:API request content types and selects response media types from Accept headers.

Example
package main

import (
	"fmt"

	jsonapi "github.com/faustbrian/go-jsonapi"
)

func main() {
	negotiator, err := jsonapi.NewNegotiator(
		nil,
		[]string{jsonapi.CursorPaginationProfileURI},
	)
	if err != nil {
		fmt.Println(err)
		return
	}

	selected, err := negotiator.NegotiateAccept(
		jsonapi.MediaTypeJSONAPI + `;profile="` +
			jsonapi.CursorPaginationProfileURI + `"`,
	)
	fmt.Println(selected.ContentType)
	fmt.Println(selected.VaryAccept)
	fmt.Println(err)
}
Output:
application/vnd.api+json; profile="http://jsonapi.org/profiles/ethanresnick/cursor-pagination/"
true
<nil>

func NewNegotiator

func NewNegotiator(extensions, profiles []string) (*Negotiator, error)

NewNegotiator constructs a negotiator from supported extension and profile URIs. Invalid or duplicate configuration is rejected before serving traffic.

func NewNegotiatorWithLimits

func NewNegotiatorWithLimits(
	extensions, profiles []string,
	limits NegotiationLimits,
) (*Negotiator, error)

NewNegotiatorWithLimits constructs a negotiator with explicit configuration and header-processing limits. Zero fields use production defaults.

func (*Negotiator) CheckContentType

func (negotiator *Negotiator) CheckContentType(header string) (MediaType, error)

CheckContentType validates the Content-Type of a JSON:API request payload. Unknown profiles are retained because profiles cannot change specification semantics; unsupported extensions fail with status 415.

func (*Negotiator) NegotiateAccept

func (negotiator *Negotiator) NegotiateAccept(header string) (NegotiatedMedia, error)

NegotiateAccept selects a JSON:API response representation from an Accept header. Invalid candidates and candidates with unsupported extensions are ignored, while unknown profiles are ignored within otherwise valid choices.

type ParameterFamily

type ParameterFamily map[string][]string

ParameterFamily preserves the decoded names and values of a JSON:API query parameter family for application-defined processing.

type PrimaryData

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

PrimaryData represents null, one resource, or a collection of resources. Construct values with NullData, ResourceData, or ResourceCollection.

func NullData

func NullData() *PrimaryData

NullData returns a primary data member whose JSON value is null.

func ResourceCollection

func ResourceCollection(resources ...ResourceObject) *PrimaryData

ResourceCollection returns a primary data member containing a resource collection. With no arguments it serializes as an empty array.

func ResourceData

func ResourceData(resource ResourceObject) *PrimaryData

ResourceData returns a primary data member containing one resource.

func (PrimaryData) MarshalJSON

func (data PrimaryData) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler.

type ProfileDefinition

type ProfileDefinition struct {
	URI              string
	ValidateDocument func(Document) error
}

ProfileDefinition declares an applied JSON:API profile and its optional document-level implementation-semantics validator.

type Query

type Query struct {
	Include        []string
	IncludePresent bool
	Fields         map[string][]string
	Sort           []SortField
	SortPresent    bool
	Page           ParameterFamily
	Filter         ParameterFamily
	Custom         map[string]ParameterFamily
	Extensions     map[string]ParameterFamily
}

Query contains parsed core query parameters and raw extension points for pagination, filtering, registered custom families, and extensions.

func ParseQuery

func ParseQuery(values url.Values) (Query, error)

ParseQuery parses core JSON:API query parameters without any custom or extension families.

Example
package main

import (
	"fmt"
	"net/url"

	jsonapi "github.com/faustbrian/go-jsonapi"
)

func main() {
	values := url.Values{
		"include":          {"author.comments"},
		"fields[articles]": {"title,body"},
		"sort":             {"-createdAt,title"},
	}
	query, err := jsonapi.ParseQuery(values)

	fmt.Println(query.Include)
	fmt.Println(query.Fields["articles"])
	fmt.Println(query.Sort[0].Name, query.Sort[0].Descending)
	fmt.Println(err)
}
Output:
[author.comments]
[title body]
createdAt true
<nil>

func ParseQueryWithLimits

func ParseQueryWithLimits(values url.Values, limits QueryLimits) (Query, error)

ParseQueryWithLimits parses core parameters with explicit decoded-query resource limits. Zero limit fields use production defaults.

type QueryError

type QueryError struct {
	Status    int
	Parameter string
	Code      string
	Message   string
}

QueryError identifies an invalid query parameter and the HTTP status required by JSON:API.

func (*QueryError) Error

func (err *QueryError) Error() string

Error implements error.

type QueryLimits

type QueryLimits struct {
	MaxParameters int
	MaxValues     int
	MaxNameBytes  int
	MaxValueBytes int
	MaxTotalBytes int
	MaxSelectors  int
	MaxListItems  int
}

QueryLimits bounds work performed on decoded URL query values. The HTTP layer remains responsible for limiting the encoded request-target length.

func DefaultQueryLimits

func DefaultQueryLimits() QueryLimits

DefaultQueryLimits returns the package's bounded query defaults.

type QueryParser

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

QueryParser recognizes core JSON:API parameters plus explicitly registered implementation and extension parameter families.

func NewQueryParser

func NewQueryParser(customFamilies, extensionNamespaces []string) (*QueryParser, error)

NewQueryParser constructs a parser with the custom family base names and extension namespaces understood by an application.

func NewQueryParserWithLimits

func NewQueryParserWithLimits(
	customFamilies, extensionNamespaces []string,
	limits QueryLimits,
) (*QueryParser, error)

NewQueryParserWithLimits constructs a parser with explicit decoded-query resource limits. Zero limit fields use production defaults.

func (*QueryParser) Parse

func (parser *QueryParser) Parse(values url.Values) (Query, error)

Parse validates and classifies decoded URL query values.

type Relationship

type Relationship struct {
	Links             Links             `json:"links,omitempty"`
	Data              *RelationshipData `json:"data,omitempty"`
	Meta              Meta              `json:"meta,omitempty"`
	AdditionalMembers Members           `json:"-"`
}

Relationship is a JSON:API relationship object.

func (Relationship) MarshalJSON

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

MarshalJSON implements json.Marshaler while preserving explicitly empty relationship links and meta objects.

type RelationshipData

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

RelationshipData represents null, one resource identifier, or a collection of resource identifiers.

func NullRelationship

func NullRelationship() *RelationshipData

NullRelationship returns relationship data whose JSON value is null.

func ToMany

func ToMany(identifiers ...Identifier) *RelationshipData

ToMany returns relationship data containing a resource identifier collection. With no arguments it serializes as an empty array.

func ToOne

func ToOne(identifier Identifier) *RelationshipData

ToOne returns relationship data containing one resource identifier.

func (RelationshipData) MarshalJSON

func (data RelationshipData) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler.

type Relationships

type Relationships map[string]Relationship

Relationships maps relationship names to relationship objects.

type ResourceObject

type ResourceObject struct {
	Type              string        `json:"type"`
	ID                string        `json:"id,omitempty"`
	LID               string        `json:"lid,omitempty"`
	Attributes        Attributes    `json:"attributes,omitempty"`
	Relationships     Relationships `json:"relationships,omitempty"`
	Links             Links         `json:"links,omitempty"`
	Meta              Meta          `json:"meta,omitempty"`
	AdditionalMembers Members       `json:"-"`
	// contains filtered or unexported fields
}

ResourceObject is a JSON:API resource object.

func (ResourceObject) MarshalJSON

func (resource ResourceObject) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler while preserving explicitly empty resource containers.

func (ResourceObject) WithID

func (resource ResourceObject) WithID(value string) ResourceObject

WithID returns a copy whose id member is present, including when value is the empty string.

func (ResourceObject) WithLID

func (resource ResourceObject) WithLID(value string) ResourceObject

WithLID returns a copy whose lid member is present, including when value is the empty string.

type SortField

type SortField struct {
	Name       string
	Descending bool
}

SortField is one ordered sorting criterion.

type ValidationContext

type ValidationContext uint8

ValidationContext identifies the protocol boundary at which a document is being validated.

const (
	// GenericDocument applies context-independent JSON:API document rules.
	GenericDocument ValidationContext = iota
	// Response applies server response identity rules.
	Response
	// CreateRequest applies resource creation request rules.
	CreateRequest
	// UpdateRequest applies resource update request rules.
	UpdateRequest
	// ToOneRelationshipRequest applies to-one relationship mutation rules.
	ToOneRelationshipRequest
	// ToManyRelationshipRequest applies to-many relationship mutation rules.
	ToManyRelationshipRequest
)

type ValidationError

type ValidationError struct {
	Violations []Violation
	// contains filtered or unexported fields
}

ValidationError reports every conformance violation found in a document.

func (*ValidationError) Error

func (err *ValidationError) Error() string

Error implements error.

func (*ValidationError) Unwrap

func (err *ValidationError) Unwrap() []error

Unwrap exposes application callback failures without including their text in the public validation message.

type ValidationOptions

type ValidationOptions struct {
	Context      ValidationContext
	ExpectedType string
	ExpectedID   string
	// ExpectedIDPresent enables endpoint identity matching when ExpectedID is
	// empty. A non-empty ExpectedID enables matching without this flag.
	ExpectedIDPresent bool
	// SparseFieldsetsOmittedLinkage applies the sole specification exception
	// to full linkage. Set it only when requested sparse fieldsets omitted the
	// relationship fields that would otherwise link included resources.
	SparseFieldsetsOmittedLinkage bool
}

ValidationOptions configures context and optional endpoint identity checks.

type Violation

type Violation struct {
	Path    string
	Code    string
	Message string
}

Violation describes one JSON:API conformance failure.

Jump to

Keyboard shortcuts

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