resources

package
v0.41.1 Latest Latest
Warning

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

Go to latest
Published: Sep 17, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package resources transforms data into the shapes a JSON response takes: conditional fields, wrapping, pagination metadata and resource collections.

Sub-packages:

resources/json    -- the JSON response building blocks
resources/jsonapi -- JsonApiResource, JsonApiRequest

JsonResource is an interface that any type can implement, and Resource is the concrete one most applications embed. A set of helper functions -- When, Unless, WhenNotNull, MergeWhen and the rest -- build JSON responses with conditional fields: when a value is missing, it is omitted from the output rather than appearing as null.

Index

Constants

View Source
const DefaultWrap = "data"

DefaultWrap is the key the outermost resource map is nested under, by default.

Variables

View Source
var ErrNotRouteBindable = errors.New("http/resources: resources may not be implicitly resolved from route bindings")

ErrNotRouteBindable is returned by ResolveRouteBinding and ResolveChildRouteBinding: a resource is a view of a model, not a thing the router can look up.

Functions

func Filter

func Filter(data map[string]any) map[string]any

Filter removes MissingValue entries from a map, and resolves MergeValue entries by merging their data into the parent.

func FlushState

func FlushState()

FlushState puts the wrapper back to "data" and turns forced wrapping off.

func ForceWrapping

func ForceWrapping(force bool)

ForceWrapping sets whether to wrap even when the resource data already carries the wrapper key.

Package-level state needs an exported function to reach it from outside the package, since an unexported field on a package variable is otherwise unreachable.

func MergeWhen

func MergeWhen(condition bool, value any) any

MergeWhen creates a MergeValue if the condition is true, otherwise returns a MissingValue.

func Transform

func Transform(value any, callback func(any) any) any

Transform applies a callback to value if value is not a MissingValue.

func Unless

func Unless(condition bool, value any) any

Unless returns value if condition is false, otherwise a MissingValue.

func When

func When(condition bool, value any) any

When returns value if condition is true, otherwise returns a MissingValue (which is filtered out during response serialization).

func WhenAggregated

func WhenAggregated(relation, column, aggregate string, loaded bool, value any) any

WhenAggregated returns value if the aggregate has been loaded.

func WhenAppended

func WhenAppended(attribute string, appended bool, value any) any

WhenAppended returns value if the attribute has been appended.

func WhenCounted

func WhenCounted(relation string, counted bool, value any) any

WhenCounted returns value if the relation has been counted.

func WhenExistsLoaded

func WhenExistsLoaded(relation string, loaded bool, value any) any

WhenExistsLoaded returns value if the existence check has been loaded.

func WhenHas

func WhenHas(data map[string]any, key string, value any) any

WhenHas returns value if the map contains the given key.

func WhenLoaded

func WhenLoaded(relation string, loaded bool, value any) any

WhenLoaded returns value if the relation is loaded on the resource. The relation parameter is the relation name; loaded reports whether the relation has been loaded.

func WhenNotNull

func WhenNotNull(value any) any

WhenNotNull returns value if it is non-nil, otherwise a MissingValue.

func WhenPivotLoaded

func WhenPivotLoaded(table string, loaded bool, value any) any

WhenPivotLoaded returns value if the pivot data is loaded for the given table.

func WhenPivotLoadedAs

func WhenPivotLoadedAs(accessor, table string, loaded bool, value any) any

WhenPivotLoadedAs returns value if the pivot data is loaded under the given accessor.

func WithoutWrapping

func WithoutWrapping()

WithoutWrapping sends the resource map at the top level, with no wrapper key.

It changes every resource in the process. JsonResponseBuilder.WithoutWrapping is the same choice for one response.

func Wrap

func Wrap(value string)

Wrap sets the string that wraps the outermost resource map.

func Wrapper

func Wrapper() string

Wrapper is the key in force, empty when wrapping is off.

Types

type AnonymousResourceCollection

type AnonymousResourceCollection struct {
	ResourceCollection
}

AnonymousResourceCollection is a ResourceCollection that also records the name of the resource type it was built from, and that is all it adds.

It exists for the ordinary index action: a handler returning a list of resources has no collection type of its own to name, but something still has to carry the wrapping and the pagination metadata for the list. Collection returns one of these, and a caller who wants the collection named declares their own type instead.

func Collection

func Collection(resources []JsonResource) *AnonymousResourceCollection

Collection is an anonymous collection of the resources, which is what a controller returns for an index action.

func NewAnonymousResourceCollection

func NewAnonymousResourceCollection(resources []JsonResource, collects string) *AnonymousResourceCollection

NewAnonymousResourceCollection creates an AnonymousResourceCollection.

func (*AnonymousResourceCollection) PreserveKeys

PreserveKeys sets whether array keys should be preserved.

type Arrayable

type Arrayable interface {
	// ToArray is the map representation.
	ToArray() map[string]any
}

Arrayable is what a wrapped value implements when it knows how to present itself as a map. Resource.ToArray looks for it before falling back to encoding/json, so a model that implements it decides exactly which fields reach the response instead of having them read off its struct tags.

type JsonResource

type JsonResource = hhttp.JsonResource

JsonResource is the interface that resource types implement. Types that implement it can be serialized to JSON responses with conditional field inclusion and wrapping.

ToArray returns the resource attributes by name; MissingValue entries are filtered out during serialization. With returns additional data to include at the top level of the response alongside the data key.

It is an alias and not a second declaration. The contract is declared in the package this one imports, because the handler-facing encoder there takes it too and cannot import this package back; one name for it in each package and two identical declarations would be one method away from being two contracts.

func CollectsResources

func CollectsResources(resource any) JsonResource

CollectsResources is a helper to wrap a single resource or a slice.

type JsonResponseBuilder

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

JsonResponseBuilder builds a JSON response from a resource.

func NewJsonResponse

func NewJsonResponse(resource JsonResource) *JsonResponseBuilder

NewJsonResponse creates a JsonResponseBuilder for the given resource.

func (*JsonResponseBuilder) Additional

func (b *JsonResponseBuilder) Additional(data map[string]any) *JsonResponseBuilder

Additional adds top-level metadata.

func (*JsonResponseBuilder) Build

func (b *JsonResponseBuilder) Build() ([]byte, error)

Build builds the JSON byte response.

func (*JsonResponseBuilder) Status

func (b *JsonResponseBuilder) Status(code int) *JsonResponseBuilder

Status sets the HTTP status code.

func (*JsonResponseBuilder) ToHTTPResponse

func (b *JsonResponseBuilder) ToHTTPResponse() *http.Response

ToHTTPResponse builds an *http.Response (useful for testing).

func (*JsonResponseBuilder) WithWrap

WithWrap sets a custom wrapper key.

func (*JsonResponseBuilder) WithoutWrapping

func (b *JsonResponseBuilder) WithoutWrapping() *JsonResponseBuilder

WithoutWrapping removes the data wrapper, returning the resource data directly at the top level.

type MergeValue

type MergeValue struct {
	Data any
}

MergeValue wraps a value that should be merged into the parent map rather than nested as a separate key.

func NewMergeValue

func NewMergeValue(data any) *MergeValue

NewMergeValue creates a MergeValue.

type MissingValue

type MissingValue struct{}

MissingValue represents a value that should be omitted from the response.

func (MissingValue) IsMissing

func (m MissingValue) IsMissing() bool

IsMissing always returns true for MissingValue.

type PaginatedResourceResponse

type PaginatedResourceResponse struct {
	Collection *ResourceCollection
	Page       int
	PerPage    int
	Total      int
	LastPage   int
}

PaginatedResourceResponse wraps a collection with pagination metadata.

func NewPaginatedResourceResponse

func NewPaginatedResourceResponse(collection *ResourceCollection, page, perPage, total int) *PaginatedResourceResponse

NewPaginatedResourceResponse creates a PaginatedResourceResponse.

func (*PaginatedResourceResponse) ToArray

func (p *PaginatedResourceResponse) ToArray() map[string]any

ToArray returns the paginated data with links and meta.

type PotentiallyMissing

type PotentiallyMissing interface {
	IsMissing() bool
}

PotentiallyMissing is the interface that wraps the IsMissing method.

Values that implement PotentiallyMissing are filtered out of JSON responses when IsMissing returns true.

type Resource

type Resource struct {
	// Resource is the thing being dressed.
	Resource any

	// WithData is what goes alongside the data key.
	WithData map[string]any

	// AdditionalData is what the caller added on the way out.
	AdditionalData map[string]any
}

Resource is one model dressed for one response.

An application either embeds Resource and shadows ToArray, or implements the JsonResource interface on its own type. Either way it goes into NewJsonResponse.

func Make

func Make(resource any) *Resource

Make is a Resource around the given value.

func (*Resource) Additional

func (r *Resource) Additional(data map[string]any) *Resource

Additional sets metadata to add to the response.

func (*Resource) GetRouteKey

func (r *Resource) GetRouteKey() any

GetRouteKey forwards to the wrapped value when it is routable, nil when it is not.

func (*Resource) GetRouteKeyName

func (r *Resource) GetRouteKeyName() string

GetRouteKeyName forwards to the wrapped value when it is routable, empty when it is not.

func (*Resource) JsonSerialize

func (r *Resource) JsonSerialize() map[string]any

JsonSerialize is an alias for Resolve.

func (*Resource) Resolve

func (r *Resource) Resolve() map[string]any

Resolve is the resource data with every missing value filtered out.

func (*Resource) ResolveChildRouteBinding

func (r *Resource) ResolveChildRouteBinding(childType string, value any, field string) (any, error)

ResolveChildRouteBinding always returns ErrNotRouteBindable.

func (*Resource) ResolveResourceData

func (r *Resource) ResolveResourceData() map[string]any

ResolveResourceData is an alias for ToAttributes.

func (*Resource) ResolveRouteBinding

func (r *Resource) ResolveRouteBinding(value any, field string) (any, error)

ResolveRouteBinding always returns ErrNotRouteBindable.

func (*Resource) Response

func (r *Resource) Response() (*hhttp.JsonResponse, error)

Response is an alias for ToResponse.

func (*Resource) ToArray

func (r *Resource) ToArray() map[string]any

ToArray is the resource as a map.

A wrapped value that is a map or an Arrayable is taken as is; anything else goes through encoding/json, which is the same set of fields the response would have carried anyway.

func (*Resource) ToAttributes

func (r *Resource) ToAttributes() map[string]any

ToAttributes is the resource's attributes.

A Go type that wants a shortcut shadows ToArray directly; this is the fallback, and calls ToArray.

func (*Resource) ToJson

func (r *Resource) ToJson() ([]byte, error)

ToJson is the JSON encoding of Resolve.

func (*Resource) ToPrettyJson

func (r *Resource) ToPrettyJson() ([]byte, error)

ToPrettyJson is the indented JSON encoding of Resolve.

func (*Resource) ToResponse

func (r *Resource) ToResponse() (*hhttp.JsonResponse, error)

ToResponse builds the resource into a *hhttp.JsonResponse, calling WithResponse on the way out.

func (*Resource) With

func (r *Resource) With() map[string]any

With is the data that goes alongside the resource.

func (*Resource) WithResponse

func (r *Resource) WithResponse(response *hhttp.JsonResponse)

WithResponse is the hook a resource overrides to touch the response on its way out.

It does nothing here. A type embedding Resource shadows it, and calls the response methods it wants.

type ResourceCollection

type ResourceCollection struct {
	Resources    []JsonResource
	PreserveKeys bool
	// contains filtered or unexported fields
}

ResourceCollection represents a collection of JsonResources.

func NewResourceCollection

func NewResourceCollection(resources []JsonResource) *ResourceCollection

NewResourceCollection creates a ResourceCollection.

func (*ResourceCollection) Collects

func (c *ResourceCollection) Collects() string

Collects returns the name of the resource class being collected.

func (*ResourceCollection) Count

func (c *ResourceCollection) Count() int

Count returns the number of resources in the collection.

func (*ResourceCollection) GetIterator

func (c *ResourceCollection) GetIterator() iter.Seq[JsonResource]

GetIterator is the resources in the collection, in order.

func (*ResourceCollection) PreserveQuery

func (c *ResourceCollection) PreserveQuery() *ResourceCollection

PreserveQuery keeps every query string parameter of the current request on the pagination links.

func (*ResourceCollection) QueryParameters

func (c *ResourceCollection) QueryParameters() (map[string]string, bool)

QueryParameters reports what ResourceCollection.PreserveQuery and ResourceCollection.WithQuery left behind: the parameters to put on the pagination links, and whether every parameter of the current request goes on them instead.

It exists because PaginatedResourceResponse needs to read this state from outside the package, and exporting the fields directly would be a second way to set what the two methods above set.

func (*ResourceCollection) ToArray

func (c *ResourceCollection) ToArray() map[string]any

ToArray implements JsonResource.

func (*ResourceCollection) With

func (c *ResourceCollection) With() map[string]any

With implements JsonResource.

func (*ResourceCollection) WithQuery

func (c *ResourceCollection) WithQuery(query map[string]string) *ResourceCollection

WithQuery sets the query string parameters that should be on the pagination links, and only those.

type UrlRoutable

type UrlRoutable interface {
	// GetRouteKey is the value that identifies the resource in a route.
	GetRouteKey() any
	// GetRouteKeyName is the name GetRouteKey's value goes by in a route.
	GetRouteKeyName() string
}

UrlRoutable is what a wrapped value implements when a URL segment can identify it: it reports the key that does the identifying and the name that key goes by in a route.

Resource.GetRouteKey and Resource.GetRouteKeyName forward to the wrapped value when it implements this, and answer empty when it does not. A resource is never routable itself -- Resource.ResolveRouteBinding always fails with ErrNotRouteBindable -- so what a resource can do is repeat the identity of the model it dresses, and no more.

Directories

Path Synopsis
Package json holds the concrete builders and response types that compose with the interfaces in the parent package hesape/http/resources.
Package json holds the concrete builders and response types that compose with the interfaces in the parent package hesape/http/resources.
Package jsonapi provides the resource types and helpers for building JSON:API-compliant responses, including sparse fieldsets, included resources, and relationship resolution.
Package jsonapi provides the resource types and helpers for building JSON:API-compliant responses, including sparse fieldsets, included resources, and relationship resolution.

Jump to

Keyboard shortcuts

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