gopcms

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

README

gopcms

Go Reference

A generic, dependency-free Go client for the PayloadCMS REST API. It's meant to be usable by any Go program — microservices, CLIs, batch jobs — that needs to query and manage PayloadCMS collections, including arbitrarily complex conditional filters.

No third-party dependencies: only the Go standard library.

Install

go get github.com/TaiBomb/gopcms

Quick start

package main

import (
	"context"
	"log"

	"github.com/TaiBomb/gopcms"
)

type Post struct {
	ID     string `json:"id"`
	Title  string `json:"title"`
	Status string `json:"status"`
	Views  int    `json:"views"`
}

func main() {
	client, err := gopcms.New("https://cms.example.com")
	if err != nil {
		log.Fatal(err)
	}
	client.SetAuth(&gopcms.APIKeyAuth{Collection: "users", APIKey: "your-api-key"})

	posts := gopcms.NewCollection[Post](client, "posts")

	result, err := posts.Find(context.Background(), &gopcms.FindOptions{
		Where: gopcms.And(
			gopcms.Equals("status", "published"),
			gopcms.GreaterThan("views", 100),
		),
		Sort:  []string{"-createdAt"},
		Limit: 10,
	})
	if err != nil {
		log.Fatal(err)
	}
	for _, p := range result.Docs {
		log.Println(p.Title)
	}
}

Filtering (conditional queries)

Every operator documented in Payload's query overview has a helper constructor:

gopcms.Equals("color", "mint")
gopcms.NotEquals("status", "draft")
gopcms.GreaterThan("views", 100)
gopcms.GreaterThanEqual("age", 18)
gopcms.LessThan("price", 50)
gopcms.LessThanEqual("stock", 0)
gopcms.Like("title", "hello world")
gopcms.Contains("description", "sale")
gopcms.In("status", "draft", "published")
gopcms.NotIn("category", "spam")
gopcms.All("tags", "go", "cms")     // MongoDB adapter only
gopcms.Exists("deletedAt", false)
gopcms.Near("location", -122.4, 37.7, 5000, 0)
gopcms.Within("location", geoJSON)
gopcms.Intersects("location", geoJSON)

Combine conditions with And / Or, nested as deeply as needed:

where := gopcms.Or(
	gopcms.Equals("color", "mint"),
	gopcms.And(
		gopcms.Equals("color", "white"),
		gopcms.Equals("featured", false),
	),
)

Nested/related properties use dot notation, exactly as in Payload:

gopcms.Exists("artists.featured", true)

Date values can be passed as a plain time.Time — it's automatically formatted as RFC3339 (in UTC), which is what PayloadCMS/MongoDB expect for date comparisons:

gopcms.GreaterThan("createdAt", time.Now().AddDate(0, 0, -7)) // last 7 days

Filters are serialized to Payload's REST bracket-notation query strings (e.g. where[or][0][color][equals]=mint) automatically — you never need to build query strings by hand.

FindOptions/DocOptions also expose Joins, for customizing Join fields (limit/sort/where per joined field, or false to disable all of them):

posts.Find(ctx, &gopcms.FindOptions{
	Joins: map[string]any{
		"relatedPosts": map[string]any{"limit": 5, "sort": "title"},
	},
})

CRUD

posts := gopcms.NewCollection[Post](client, "posts")

// Find (list) / FindByID / Count
result, err := posts.Find(ctx, &gopcms.FindOptions{Where: gopcms.Equals("status", "published")})
doc, err := posts.FindByID(ctx, "64f...", nil)
count, err := posts.Count(ctx, &gopcms.CountOptions{Where: gopcms.Equals("status", "draft")})

// Create / Update / Delete
created, err := posts.Create(ctx, map[string]any{"title": "Hello"}, nil)
updated, err := posts.Update(ctx, "64f...", map[string]any{"title": "Updated"}, nil)
deleted, err := posts.Delete(ctx, "64f...", nil)

// Bulk update / delete (require a non-empty Where)
bulkUpdated, err := posts.UpdateMany(ctx, gopcms.Equals("status", "draft"), map[string]any{"status": "archived"}, nil)
bulkDeleted, err := posts.DeleteMany(ctx, gopcms.LessThan("createdAt", "2020-01-01"), nil)
Iterating over every page

Collection.All transparently walks through every page of a query, using Go's range-over-func iterators (Go 1.23+):

for post, err := range posts.All(ctx, &gopcms.FindOptions{Where: gopcms.Equals("status", "published")}) {
	if err != nil {
		log.Fatal(err) // a Find call failed; iteration has already stopped
	}
	fmt.Println(post.Title)
}

Break out of the loop (or cancel ctx) at any point and no further requests are made.

Schema-agnostic usage

T can be a struct for type safety, or map[string]any / json.RawMessage for fully dynamic, schema-agnostic access — handy for a library that different services with different Payload schemas will reuse:

posts := gopcms.NewCollection[map[string]any](client, "posts")

Authentication

Two strategies are supported, both configurable per Client:

// API key (server-to-server, e.g. microservices)
client.SetAuth(&gopcms.APIKeyAuth{Collection: "users", APIKey: "..."})

// Email/password JWT
jwt := gopcms.NewJWTAuth("")
client.SetAuth(jwt)

users := gopcms.NewAuthCollection[User](client, "users", jwt)
login, err := users.Login(ctx, "dev@example.com", "secret")
// jwt's token is now set automatically; every subsequent Client call is authenticated.

me, err := users.Me(ctx)
refreshed, err := users.Refresh(ctx)
_, err = users.Logout(ctx, false)

AuthCollection also exposes Verify, Unlock, ForgotPassword and ResetPassword, matching Payload's auth operations.

Auto-refresh on 401: call EnableAutoRefresh once after login to have the underlying JWTAuth transparently call Refresh and retry a request that came back 401, instead of failing outright:

users := gopcms.NewAuthCollection[User](client, "users", jwt)
if _, err := users.Login(ctx, "dev@example.com", "secret"); err != nil {
	log.Fatal(err)
}
if err := users.EnableAutoRefresh(); err != nil {
	log.Fatal(err)
}
// Any later call that gets a 401 now triggers one automatic Refresh + retry
// before the error is returned to you.

Globals

type SiteSettings struct {
	SiteName string `json:"siteName"`
}

settings := gopcms.NewGlobal[SiteSettings](client, "site-settings")
doc, err := settings.Get(ctx, nil)
updated, err := settings.Update(ctx, map[string]any{"siteName": "New name"}, nil)

Uploads

For upload-enabled collections (e.g. a "media" collection), CreateWithFile / UpdateWithFile send a multipart/form-data request per Payload's upload docs: the file goes in a file part, and any other fields (like alt) are JSON-encoded into a _payload part.

type Media struct {
	ID  string `json:"id"`
	Alt string `json:"alt"`
}

media := gopcms.NewCollection[Media](client, "media")

f, err := os.Open("photo.jpg")
if err != nil {
	log.Fatal(err)
}
defer f.Close()

created, err := media.CreateWithFile(ctx, gopcms.UploadFile{
	Reader:   f,
	Filename: "photo.jpg",
	// ContentType is optional; inferred from the extension if omitted.
}, map[string]any{"alt": "A photo"}, nil)

// Re-upload (replace) an existing document's file:
updated, err := media.UpdateWithFile(ctx, created.Doc.ID, gopcms.UploadFile{
	Reader:   anotherReader,
	Filename: "photo-v2.jpg",
}, map[string]any{"alt": "Updated photo"}, nil)

gopcms.NewUploadFileFromPath(path) is a shortcut that opens a local file and closes it automatically once the request completes:

file, err := gopcms.NewUploadFileFromPath("photo.jpg")
if err != nil {
	log.Fatal(err)
}
created, err := media.CreateWithFile(ctx, file, map[string]any{"alt": "A photo"}, nil)

Versions & drafts

For collections/globals with versions enabled, you can list a document's version history, fetch a single version, and restore a document to a prior version, per Payload's versions docs:

// List a document's version history (versions belonging to a specific parent):
versions, err := posts.FindVersions(ctx, &gopcms.FindOptions{
	Where: gopcms.Equals("parent", "64f..."),
	Sort:  []string{"-createdAt"},
})
for _, v := range versions.Docs {
	log.Println(v.ID, v.CreatedAt, v.Version.Title) // v.Version is a Post
}

// Fetch a single version by its own ID:
version, err := posts.FindVersionByID(ctx, "64a...", nil)

// Restore the parent document to that version's state:
restored, err := posts.RestoreVersion(ctx, "64a...", nil)
log.Println(restored.Doc.Title)

The same three methods (FindVersions, FindVersionByID, RestoreVersion) exist on Global[T], operating on /api/globals/{slug}/versions instead.

Preferences

Typed access to Payload's Preferences API, scoped to the currently authenticated user:

type RegionPref struct {
	Timezone string `json:"timezone"`
}

prefs := gopcms.NewPreferences[RegionPref](client)

pref, err := prefs.Get(ctx, "region")
set, err := prefs.Set(ctx, "region", RegionPref{Timezone: "Europe/Rome"})
_, err = prefs.Delete(ctx, "region")

T can just as well be a primitive (string, int, ...) or map[string]any for preference values without a fixed shape.

Access control

Typed-ish wrappers around Payload's Access API — pass any out (typically map[string]any or a custom struct matching your access-control shape):

var appAccess map[string]any
err := client.Access(ctx, &appAccess) // GET /api/access

var docAccess map[string]any
err = posts.Access(ctx, "64f...", &docAccess) // GET /api/posts/access/64f...

var globalAccess map[string]any
err = settings.Access(ctx, &globalAccess) // GET /api/globals/site-settings/access

Errors

Every non-2xx response is returned as *gopcms.APIError, carrying the HTTP status code and every error message Payload returned:

_, err := posts.FindByID(ctx, "missing-id", nil)
if gopcms.IsNotFound(err) {
	// ...
}
if apiErr, ok := gopcms.AsAPIError(err); ok {
	log.Println(apiErr.StatusCode, apiErr.Message())
}

Helpers: IsNotFound, IsUnauthorized, IsForbidden, IsValidationError.

Escape hatch: custom endpoints

Collection/Global/AuthCollection cover the standard CRUD, auth, versions, Preferences and Access operations, but PayloadCMS configs are highly customizable — custom endpoints declared in your own Payload config, for instance. Client.Do / Client.DoPublic expose the same request/response handling (auth, retries, error parsing, method-override) the rest of the library uses internally, for anything not wrapped yet:

var result MyCustomResponse
err := client.Do(ctx, http.MethodGet, "/posts/123/tracking", nil, nil, &result)

// DoPublic skips applying the configured Authenticator, for intentionally
// public custom endpoints.
err = client.DoPublic(ctx, http.MethodPost, "/some-public-endpoint", nil, requestBody, &result)

path is relative to the configured API prefix (default /api), same as every other method in the library. For file uploads to custom endpoints, Client.DoMultipart is the equivalent raw entry point used internally by CreateWithFile/UpdateWithFile.

Reliability

Long queries: GET requests whose URL would exceed a practical length (2000 characters by default) are transparently retried using Payload's method override (POST + X-Payload-HTTP-Method-Override: GET). This just works — no code changes needed — but the threshold is adjustable with WithMaxGETURLLength, or disabled with WithMaxGETURLLength(0).

Retries: disabled by default. Enable them with WithRetry for transient network errors or 429/502/503/504 responses on idempotent requests (GET, HEAD, DELETE) — Create (POST) is deliberately never auto-retried, since retrying it could create duplicate documents:

client, err := gopcms.New("https://cms.example.com",
	gopcms.WithRetry(gopcms.DefaultRetryPolicy()), // 3 retries, 200ms base delay, 2s cap, with jitter
)

If a 429/503 response includes a Retry-After header (either as seconds or an HTTP date, per RFC 9110), that value is honored instead of the exponential backoff delay — still clamped to the policy's MaxDelay so a server can't force an arbitrarily long wait.

Auto-refresh on 401 (JWT only): see Authentication — a 401 triggers one Refresher.Refresh attempt and request retry, independent of RetryPolicy, whenever the configured Authenticator supports it.

Observability: register an Observer to get notified of every physical HTTP request/response (including individual retry attempts) for logging or metrics, without needing a custom http.RoundTripper:

client, err := gopcms.New("https://cms.example.com",
	gopcms.WithObserver(gopcms.ObserverFunc{
		Response: func(ctx context.Context, method, url string, statusCode int, dur time.Duration, err error) {
			log.Printf("%s %s -> %d (%s) err=%v", method, url, statusCode, dur, err)
		},
	}),
)

Options

By default, New gives the Client its own *http.Client with a DefaultHTTPTimeout (30s) — never the bare http.DefaultClient, which has no timeout at all and would otherwise let a request hang indefinitely if you forget to pass a context with a deadline. Adjust it with WithTimeout, or replace the whole http.Client (e.g. for a custom Transport) with WithHTTPClient:

client, err := gopcms.New("https://cms.example.com",
	gopcms.WithHTTPClient(customHTTPClient),
	gopcms.WithTimeout(10 * time.Second), // adjust just the timeout; apply after WithHTTPClient to override its timeout too
	gopcms.WithAPIPrefix("custom-api"), // if routes.api isn't the default "/api"
	gopcms.WithAuth(&gopcms.APIKeyAuth{Collection: "users", APIKey: "..."}),
	gopcms.WithUserAgent("my-service/1.0"),
	gopcms.WithMaxGETURLLength(0), // disable the automatic GET-via-POST fallback
	gopcms.WithRetry(gopcms.DefaultRetryPolicy()),
	gopcms.WithObserver(myObserver),
)

Testing

go build ./... && go vet ./... && go test ./... -race

Tests use net/http/httptest and don't require a running PayloadCMS instance.

License

Apache License 2.0.

Documentation

Overview

Package gopcms is a generic, dependency-free Go client for the PayloadCMS REST API (https://payloadcms.com).

It is designed to be used by any Go program — a microservice, a CLI, a batch job, etc. — that needs to talk to a PayloadCMS instance: querying collections with arbitrarily complex conditional filters, running CRUD operations, authenticating via API key or JWT, and working with Globals.

Quick start

client, err := gopcms.New("https://cms.example.com")
if err != nil {
	log.Fatal(err)
}
client.SetAuth(&gopcms.APIKeyAuth{Collection: "users", APIKey: "..."})

type Post struct {
	ID    string `json:"id"`
	Title string `json:"title"`
}

posts := gopcms.NewCollection[Post](client, "posts")

result, err := posts.Find(ctx, &gopcms.FindOptions{
	Where: gopcms.And(
		gopcms.Equals("status", "published"),
		gopcms.GreaterThan("views", 100),
	),
	Sort:  []string{"-createdAt"},
	Limit: 10,
})

Collections can also be queried without declaring a struct, by using map[string]any (or json.RawMessage) as the type parameter, e.g. gopcms.NewCollection[map[string]any](client, "posts").

Example

This example is intentionally not executed (it has no "Output:" comment and talks to a real server): it exists to show up in package documentation on pkg.go.dev / `go doc`.

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/TaiBomb/gopcms"
)

// Post is a minimal example collection type.
type Post struct {
	ID     string `json:"id"`
	Title  string `json:"title"`
	Status string `json:"status"`
	Views  int    `json:"views"`
}

func main() {
	client, err := gopcms.New("https://cms.example.com")
	if err != nil {
		log.Fatal(err)
	}
	client.SetAuth(&gopcms.APIKeyAuth{Collection: "users", APIKey: "your-api-key"})

	posts := gopcms.NewCollection[Post](client, "posts")

	result, err := posts.Find(context.Background(), &gopcms.FindOptions{
		Where: gopcms.And(
			gopcms.Equals("status", "published"),
			gopcms.GreaterThan("views", 100),
		),
		Sort:  []string{"-createdAt"},
		Limit: 10,
	})

	if err != nil {
		log.Fatal(err)
	}

	for _, p := range result.Docs {
		fmt.Println(p.Title)
	}
}

Index

Examples

Constants

View Source
const DefaultAPIPrefix = "/api"

DefaultAPIPrefix is the default path segment PayloadCMS mounts its REST API under.

View Source
const DefaultHTTPTimeout = 30 * time.Second

DefaultHTTPTimeout is the timeout applied to the Client's default http.Client. http.DefaultClient (Go's zero-value *http.Client) has no timeout at all, which means a request can hang indefinitely if the caller doesn't pass a context with a deadline. New builds its own *http.Client with this timeout instead of reusing http.DefaultClient, so a sane bound exists even if the caller forgets to set one. Override it with WithTimeout or replace the whole http.Client with WithHTTPClient.

View Source
const DefaultMaxGETURLLength = 2000

DefaultMaxGETURLLength is the default threshold (in characters) beyond which a GET request is transparently switched to Payload's "method override" mechanism (POST with X-Payload-HTTP-Method-Override: GET), to avoid failing against servers/proxies that reject very long URLs. See https://payloadcms.com/docs/rest-api/overview#method-override-for-get-requests.

View Source
const DefaultPingPath = "/access"

DefaultPingPath is the endpoint Ping targets by default. PayloadCMS does not ship a dedicated health check route, but /access is guaranteed to exist on every instance regardless of which collections/globals are configured, making it the cheapest reliable proxy for "the server is up and its routes are initialized".

Variables

View Source
var ErrNoToken = errors.New("no JWT token set; call Login or SetToken first")

ErrNoToken is returned by JWTAuth when ApplyAuth is called before a token has been set (e.g. before calling Login).

Functions

func BoolPtr

func BoolPtr(v bool) *bool

BoolPtr is a small helper to obtain a *bool inline, e.g. FindOptions{Pagination: gopcms.BoolPtr(false)}.

func IntPtr

func IntPtr(v int) *int

IntPtr is a small helper to obtain an *int inline, e.g. FindOptions{Depth: gopcms.IntPtr(0)}.

func IsForbidden

func IsForbidden(err error) bool

IsForbidden reports whether err represents a 403 Forbidden response.

func IsNotFound

func IsNotFound(err error) bool

IsNotFound reports whether err represents a 404 Not Found response.

func IsUnauthorized

func IsUnauthorized(err error) bool

IsUnauthorized reports whether err represents a 401 Unauthorized response.

func IsValidationError

func IsValidationError(err error) bool

IsValidationError reports whether err represents a 400 Bad Request response, which PayloadCMS uses for field validation failures.

Types

type APIErr

type APIErr struct {
	Message string          `json:"message"`
	Name    string          `json:"name,omitempty"`
	Data    json.RawMessage `json:"data,omitempty"`
}

APIErr represents a single error entry as returned by PayloadCMS in the body of a non-2xx response: {"errors": [{"message": "...", ...}]}.

type APIError

type APIError struct {
	StatusCode int
	Errors     []APIErr
	// RawBody holds the original response body, in case it did not match
	// PayloadCMS's usual {"errors": [...]} shape (e.g. a proxy error page).
	RawBody []byte
}

APIError is returned by every Client/Collection/Global method when PayloadCMS responds with a non-2xx HTTP status. It carries the HTTP status code plus every individual error message Payload returned.

func AsAPIError

func AsAPIError(err error) (*APIError, bool)

AsAPIError extracts an *APIError from err, if present, using errors.As.

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) Message

func (e *APIError) Message() string

Message returns the first error message, or an empty string if none was present in the response body.

type APIKeyAuth

type APIKeyAuth struct {
	// Collection is the slug of the auth-enabled collection the key
	// belongs to (e.g. "users" or "api-clients").
	Collection string
	// APIKey is the key value assigned to a user document.
	APIKey string
}

APIKeyAuth authenticates requests using a PayloadCMS API key, as described at https://payloadcms.com/docs/authentication/api-keys.

The resulting header looks like:

Authorization: <collection-slug> API-Key <api-key>

func (*APIKeyAuth) ApplyAuth

func (a *APIKeyAuth) ApplyAuth(_ context.Context, req *http.Request) error

ApplyAuth implements Authenticator.

type AuthCollection

type AuthCollection[T any] struct {
	*Collection[T]
	// contains filtered or unexported fields
}

AuthCollection wraps a Collection for an auth-enabled PayloadCMS collection (i.e. one with auth: true in its config), adding Login, Logout, Refresh, Me and password-management operations, as documented at https://payloadcms.com/docs/authentication/operations.

If constructed with a non-nil *JWTAuth, a successful Login/Refresh will automatically update that JWTAuth's token, and Logout will clear it — so the same Client used for regular collection calls stays authenticated transparently.

func NewAuthCollection

func NewAuthCollection[T any](client *Client, slug string, jwt *JWTAuth) *AuthCollection[T]

NewAuthCollection creates an AuthCollection handle for the given auth-enabled collection slug. jwt may be nil if you intend to manage tokens yourself (e.g. reading LoginResult.Token and wiring it up to a JWTAuth manually).

Example

ExampleNewAuthCollection shows logging in once via email/password and having every subsequent Client call (across any Collection built on the same Client) authenticated automatically.

package main

import (
	"context"
	"log"

	"github.com/TaiBomb/gopcms"
)

// Post is a minimal example collection type.
type Post struct {
	ID     string `json:"id"`
	Title  string `json:"title"`
	Status string `json:"status"`
	Views  int    `json:"views"`
}

func main() {
	client, err := gopcms.New("https://cms.example.com")
	if err != nil {
		log.Fatal(err)
	}

	jwt := gopcms.NewJWTAuth("")
	client.SetAuth(jwt)

	type User struct {
		ID    string `json:"id"`
		Email string `json:"email"`
	}

	users := gopcms.NewAuthCollection[User](client, "users", jwt)
	if _, err := users.Login(context.Background(), "dev@example.com", "secret"); err != nil {
		log.Fatal(err)
	}

	// jwt's token is now set; every collection built on `client` is
	// authenticated from here on.
	posts := gopcms.NewCollection[Post](client, "posts")
	_, _ = posts.Find(context.Background(), nil)
}

func (*AuthCollection[T]) EnableAutoRefresh

func (a *AuthCollection[T]) EnableAutoRefresh() error

EnableAutoRefresh wires this AuthCollection's Refresh operation into its JWTAuth, so that any request made through the Client that comes back 401 Unauthorized automatically triggers one token refresh and one retry of the original request -- see Refresher. Requires that this AuthCollection was constructed with a non-nil *JWTAuth (the jwt argument to NewAuthCollection).

func (*AuthCollection[T]) ForgotPassword

func (a *AuthCollection[T]) ForgotPassword(ctx context.Context, email string) (*MessageResult, error)

ForgotPassword triggers PayloadCMS's password-reset email flow for the given address.

func (*AuthCollection[T]) Login

func (a *AuthCollection[T]) Login(ctx context.Context, email, password string) (*LoginResult[T], error)

Login authenticates with an email/password pair.

func (*AuthCollection[T]) Logout

func (a *AuthCollection[T]) Logout(ctx context.Context, allSessions bool) (*MessageResult, error)

Logout invalidates the current session. If allSessions is true, every active session for the user is ended.

func (*AuthCollection[T]) Me

func (a *AuthCollection[T]) Me(ctx context.Context) (*MeResult[T], error)

Me returns the currently authenticated user for the request, or a nil User if unauthenticated.

func (*AuthCollection[T]) Refresh

func (a *AuthCollection[T]) Refresh(ctx context.Context) (*RefreshResult[T], error)

Refresh exchanges a still-valid JWT for a new one with a renewed expiration. Requires that the Client is currently authenticated (e.g. via the JWTAuth passed to NewAuthCollection).

func (*AuthCollection[T]) ResetPassword

func (a *AuthCollection[T]) ResetPassword(ctx context.Context, token, newPassword string) (*LoginResult[T], error)

ResetPassword completes the password-reset flow using the token received via the forgot-password email, setting a new password. On success, it logs the user in, same as Login.

func (*AuthCollection[T]) Unlock

func (a *AuthCollection[T]) Unlock(ctx context.Context, email string) (*MessageResult, error)

Unlock removes a login-attempts lockout for the user identified by email.

func (*AuthCollection[T]) Verify

func (a *AuthCollection[T]) Verify(ctx context.Context, token string) (*MessageResult, error)

Verify confirms a user's email address using the token sent in the verification email.

type Authenticator

type Authenticator interface {
	ApplyAuth(ctx context.Context, req *http.Request) error
}

Authenticator applies authentication information to an outgoing request.

type BulkDeleteResult

type BulkDeleteResult[T any] struct {
	Docs    []T           `json:"docs"`
	Errors  []BulkOpError `json:"errors,omitempty"`
	Message string        `json:"message"`
}

BulkDeleteResult is the shape returned by PayloadCMS's bulk Delete operation (DELETE on the collection root, filtered by Where).

type BulkOpError

type BulkOpError struct {
	ID      any    `json:"id"`
	Message string `json:"message"`
}

BulkOpError represents a single failure entry within a bulk update/delete response's "errors" array.

type BulkUpdateResult

type BulkUpdateResult[T any] struct {
	Docs    []T           `json:"docs"`
	Errors  []BulkOpError `json:"errors,omitempty"`
	Message string        `json:"message"`
}

BulkUpdateResult is the shape returned by PayloadCMS's bulk Update operation (PATCH on the collection root, filtered by Where).

type Client

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

Client is a thin HTTP wrapper around a PayloadCMS REST API instance. Create one Client per PayloadCMS base URL and reuse it across Collection / Global instances.

func New

func New(baseURL string, opts ...Option) (*Client, error)

New creates a Client targeting the given PayloadCMS base URL. The base URL must not include the "/api" suffix; use WithAPIPrefix if the instance mounts the REST API somewhere other than the default.

func (*Client) Access

func (c *Client) Access(ctx context.Context, out any) error

Access retrieves the overall Access Control matrix for the currently authenticated user, across every collection/global (which operations they can perform, down to individual fields). See https://payloadcms.com/docs/authentication/operations#access.

func (*Client) Do

func (c *Client) Do(ctx context.Context, method, path string, query url.Values, body any, out any) error

Do performs a raw, authenticated request against the PayloadCMS REST API and decodes a successful (2xx) JSON response into out (nil discards the body). It exists as an escape hatch for custom endpoints defined on the PayloadCMS instance.

path is relative to the configured API prefix, e.g. "/payload-preferences/my-key" or "/posts/123/some-custom-route". query may be nil.

GET requests whose resulting URL would exceed the configured max-GET-URL-length are automatically retried using Payload's method override mechanism; see WithMaxGETURLLength.

func (*Client) DoPublic

func (c *Client) DoPublic(ctx context.Context, method, path string, query url.Values, body any, out any) error

DoPublic is identical to Do but does not apply the configured Authenticator, for custom endpoints that are intentionally public.

func (*Client) Ping added in v0.0.2

func (c *Client) Ping(ctx context.Context) error

Ping performs a lightweight liveness check against the configured PayloadCMS instance by requesting DefaultPingPath. A nil error means the instance responded with a 2xx status; any other outcome (network error, timeout, non-2xx response) is returned as-is.

It intentionally bypasses the configured Authenticator (see Client.DoPublic): the goal is to confirm the server is reachable and serving, not to validate credentials, so Ping still succeeds even if the API key/JWT in use has expired.

func (*Client) PingPath added in v0.0.2

func (c *Client) PingPath(ctx context.Context, path string) error

PingPath is like Ping but targets a custom path instead of DefaultPingPath, e.g. a custom endpoint registered via the `endpoints` array in payload.config (such as "/health").

func (*Client) SetAuth

func (c *Client) SetAuth(a Authenticator)

SetAuth replaces the Authenticator used for subsequent requests.

type Collection

type Collection[T any] struct {
	// contains filtered or unexported fields
}

Collection is a generic, type-safe handle onto a single PayloadCMS collection, identified by its slug. T is the Go type used to decode (and encode) documents; it may be a user-defined struct for type safety, or map[string]any / json.RawMessage for a fully dynamic, schema-agnostic usage.

func NewCollection

func NewCollection[T any](client *Client, slug string) *Collection[T]

NewCollection creates a Collection handle for the given slug.

func (*Collection[T]) Access

func (c *Collection[T]) Access(ctx context.Context, id any, out any) error

Access retrieves the current user's Access Control permissions for this specific document (create/read/update/delete, down to individual fields).

func (*Collection[T]) All

func (c *Collection[T]) All(ctx context.Context, opts *FindOptions) iter.Seq2[T, error]

All returns an iterator over every document matching opts, transparently issuing as many Find calls as needed to walk through all pages. opts.Page (if set) is used as the starting page; opts.Limit, when left at 0, uses PayloadCMS's own default page size.

Range over it like:

for doc, err := range posts.All(ctx, opts) {
	if err != nil {
		log.Println(err)
		break
	}
	fmt.Println(doc.Title)
}

If a Find call fails partway through, the error is yielded once (with a zero value for doc) and iteration stops. Breaking out of the range loop, or canceling ctx, also stops iteration early -- no further HTTP requests are made once that happens.

Example

ExampleCollection_All shows the auto-paginating iterator, which transparently issues as many Find calls as needed.

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/TaiBomb/gopcms"
)

// Post is a minimal example collection type.
type Post struct {
	ID     string `json:"id"`
	Title  string `json:"title"`
	Status string `json:"status"`
	Views  int    `json:"views"`
}

func main() {
	client, err := gopcms.New("https://cms.example.com")
	if err != nil {
		log.Fatal(err)
	}
	posts := gopcms.NewCollection[Post](client, "posts")

	ctx := context.Background()
	for post, err := range posts.All(ctx, &gopcms.FindOptions{Limit: 100}) {
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(post.Title)
	}
}

func (*Collection[T]) Count

func (c *Collection[T]) Count(ctx context.Context, opts *CountOptions) (*CountResult, error)

Count returns the number of documents matching opts.

func (*Collection[T]) Create

func (c *Collection[T]) Create(ctx context.Context, data any, opts *DocOptions) (*CreateResult[T], error)

Create creates a new document. data is typically a struct or map representing the fields to set.

func (*Collection[T]) CreateWithFile

func (c *Collection[T]) CreateWithFile(ctx context.Context, file UploadFile, data any, opts *DocOptions) (*CreateResult[T], error)

CreateWithFile creates a new document in an upload-enabled collection, attaching a binary file alongside the rest of the document's fields. data is optional and, like Create, is typically a struct or map holding fields such as "alt" or "title" as defined on the collection.

PayloadCMS expects this as a multipart/form-data request: the file is sent under the "file" field, and data (if any) is JSON-encoded into a "_payload" field.

func (*Collection[T]) Delete

func (c *Collection[T]) Delete(ctx context.Context, id any, opts *DocOptions) (*DeleteResult[T], error)

Delete deletes a single document by ID.

func (*Collection[T]) DeleteMany

func (c *Collection[T]) DeleteMany(ctx context.Context, where Where, opts *DocOptions) (*BulkDeleteResult[T], error)

DeleteMany bulk-deletes every document matching where. where must not be empty: PayloadCMS requires an explicit filter for bulk deletes.

func (*Collection[T]) Find

func (c *Collection[T]) Find(ctx context.Context, opts *FindOptions) (*PaginatedDocs[T], error)

Find lists documents matching opts (filters, sort, pagination, ...). See https://payloadcms.com/docs/queries/overview.

func (*Collection[T]) FindByID

func (c *Collection[T]) FindByID(ctx context.Context, id any, opts *DocOptions) (*T, error)

FindByID retrieves a single document by its ID.

func (*Collection[T]) FindVersionByID

func (c *Collection[T]) FindVersionByID(ctx context.Context, versionID string, opts *DocOptions) (*Version[T], error)

FindVersionByID retrieves a single stored version by its own ID (not the parent document's ID).

func (*Collection[T]) FindVersions

func (c *Collection[T]) FindVersions(ctx context.Context, opts *FindOptions) (*PaginatedDocs[Version[T]], error)

FindVersions lists the stored versions of documents in this collection. Use opts.Where (e.g. gopcms.Equals("parent", docID)) to scope it to a single document's version history.

func (*Collection[T]) RestoreVersion

func (c *Collection[T]) RestoreVersion(ctx context.Context, versionID string, opts *DocOptions) (*RestoreVersionResult[T], error)

RestoreVersion restores the parent document to the state captured by the given version ID.

func (*Collection[T]) Slug

func (c *Collection[T]) Slug() string

Slug returns the collection's slug.

func (*Collection[T]) Update

func (c *Collection[T]) Update(ctx context.Context, id any, data any, opts *DocOptions) (*UpdateResult[T], error)

Update updates a single document by ID.

func (*Collection[T]) UpdateMany

func (c *Collection[T]) UpdateMany(ctx context.Context, where Where, data any, opts *DocOptions) (*BulkUpdateResult[T], error)

UpdateMany bulk-updates every document matching where, setting the fields present in data. where must not be empty: PayloadCMS requires an explicit filter for bulk updates.

func (*Collection[T]) UpdateWithFile

func (c *Collection[T]) UpdateWithFile(ctx context.Context, id any, file UploadFile, data any, opts *DocOptions) (*UpdateResult[T], error)

UpdateWithFile updates a single document by ID, replacing (re-uploading) its file. Payload treats this identically to Create in terms of wire format: the file goes under "file" and any other fields under a JSON-encoded "_payload" field.

type CountOptions

type CountOptions struct {
	Where  Where
	Locale string
}

CountOptions controls a Collection.Count request.

type CountResult

type CountResult struct {
	TotalDocs int `json:"totalDocs"`
}

CountResult is the shape returned by PayloadCMS's Count operation.

type CreateResult

type CreateResult[T any] struct {
	Doc     T        `json:"doc"`
	Message string   `json:"message"`
	Errors  []APIErr `json:"errors,omitempty"`
}

CreateResult is the shape returned by PayloadCMS's Create operation.

type DeleteResult

type DeleteResult[T any] struct {
	Doc     T      `json:"doc"`
	Message string `json:"message"`
}

DeleteResult is the shape returned by PayloadCMS's Delete-by-ID operation.

type DocOptions

type DocOptions struct {
	Depth          *int
	Locale         string
	FallbackLocale string
	Select         map[string]any
	Populate       map[string]any
	Draft          *bool

	// Joins customizes the request for Join fields; see FindOptions.Joins.
	Joins any
}

DocOptions controls single-document operations (FindByID, Create, Update, Delete). All fields are optional.

type FindOptions

type FindOptions struct {
	// Where is the (possibly nested, via And/Or) conditional filter.
	Where Where

	// Sort lists fields to sort by, in order. Prefix a field with "-" for
	// descending order, e.g. []string{"-createdAt", "title"}.
	Sort []string

	// Limit caps the number of documents returned. 0 means "use the
	// collection's default limit".
	Limit int

	// Page selects which page to return when used together with Limit.
	Page int

	// Depth controls how many levels of relationships/uploads are
	// automatically populated. A pointer distinguishes "unset" from "0"
	// (0 disables population entirely).
	Depth *int

	// Locale retrieves localized document(s) in a specific locale.
	Locale string

	// FallbackLocale specifies a fallback locale if no localized value
	// exists for Locale.
	FallbackLocale string

	// Select restricts which fields are returned. Set a field to true to
	// include it or false to exclude it (do not mix true/false at the same
	// nesting level, per Payload's Select API).
	Select map[string]any

	// Populate specifies which fields to include from populated
	// (relationship/upload) documents, keyed by collection slug.
	Populate map[string]any

	// Pagination disables Payload's pagination wrapper when set to false.
	// Leave nil to use the default (paginated) behavior.
	Pagination *bool

	// Draft includes draft documents when the collection has drafts
	// enabled.
	Draft *bool

	// Joins customizes the request for Join fields, keyed by field name,
	// e.g. map[string]any{"relatedPosts": map[string]any{"limit": 5, "sort": "title"}}.
	// Set it to false (instead of a map) to disable all Join fields from
	// being populated. See https://payloadcms.com/docs/fields/join#rest-api.
	Joins any
}

FindOptions controls a Collection.Find (list) request. All fields are optional; the zero value performs an unfiltered, default-paginated query.

type Global

type Global[T any] struct {
	// contains filtered or unexported fields
}

Global is a generic, type-safe handle onto a single PayloadCMS Global, identified by its slug. Globals cannot be created or deleted — only read and updated — as documented at https://payloadcms.com/docs/rest-api/overview#globals.

func NewGlobal

func NewGlobal[T any](client *Client, slug string) *Global[T]

NewGlobal creates a Global handle for the given slug.

func (*Global[T]) Access

func (g *Global[T]) Access(ctx context.Context, out any) error

Access retrieves the current user's Access Control permissions for this Global.

func (*Global[T]) FindVersionByID

func (g *Global[T]) FindVersionByID(ctx context.Context, versionID string, opts *DocOptions) (*Version[T], error)

FindVersionByID retrieves a single stored version of this Global by its own ID.

func (*Global[T]) FindVersions

func (g *Global[T]) FindVersions(ctx context.Context, opts *FindOptions) (*PaginatedDocs[Version[T]], error)

FindVersions lists the stored versions of this Global.

func (*Global[T]) Get

func (g *Global[T]) Get(ctx context.Context, opts *DocOptions) (*T, error)

Get retrieves the global's current document.

func (*Global[T]) RestoreVersion

func (g *Global[T]) RestoreVersion(ctx context.Context, versionID string, opts *DocOptions) (*RestoreVersionResult[T], error)

RestoreVersion restores this Global to the state captured by the given version ID.

func (*Global[T]) Slug

func (g *Global[T]) Slug() string

Slug returns the global's slug.

func (*Global[T]) Update

func (g *Global[T]) Update(ctx context.Context, data any, opts *DocOptions) (*GlobalUpdateResult[T], error)

Update replaces (merges) the global's data.

type GlobalUpdateResult

type GlobalUpdateResult[T any] struct {
	Doc     T
	Message string
}

GlobalUpdateResult is returned by Global.Update. PayloadCMS returns the updated global's fields at the top level of the response, alongside a sibling "message" field (unlike collection updates, which nest the document under "doc"). Message is extracted on a best-effort basis, since its exact presence can vary across Payload versions.

type JWTAuth

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

JWTAuth authenticates requests using a bearer-style JWT.

Authorization: JWT <token>

func NewJWTAuth

func NewJWTAuth(token string) *JWTAuth

NewJWTAuth creates a JWTAuth. Token may be empty if it will be populated later via SetToken or AuthCollection.Login.

func (*JWTAuth) ApplyAuth

func (a *JWTAuth) ApplyAuth(_ context.Context, req *http.Request) error

ApplyAuth implements Authenticator.

func (*JWTAuth) Refresh

func (a *JWTAuth) Refresh(ctx context.Context) error

Refresh implements the optional Refresher interface: it calls the function registered via SetRefreshFunc and, on success, updates the token used for subsequent requests.

func (*JWTAuth) SetRefreshFunc

func (a *JWTAuth) SetRefreshFunc(fn func(ctx context.Context) (string, error))

SetRefreshFunc registers a function used to obtain a fresh token automatically when a request fails with 401 Unauthorized (see Refresher). fn is typically wired up via AuthCollection.EnableAutoRefresh rather than called directly.

func (*JWTAuth) SetToken

func (a *JWTAuth) SetToken(token string)

SetToken updates the token used for subsequent requests.

func (*JWTAuth) Token

func (a *JWTAuth) Token() string

Token returns the currently configured token.

type LoginResult

type LoginResult[T any] struct {
	Message string `json:"message,omitempty"`
	User    T      `json:"user"`
	Token   string `json:"token"`
	Exp     int64  `json:"exp"`
}

LoginResult is returned by AuthCollection.Login, AuthCollection.ResetPassword, matching https://payloadcms.com/docs/authentication/operations#login

type MeResult

type MeResult[T any] struct {
	User  *T     `json:"user"`
	Token string `json:"token,omitempty"`
	Exp   int64  `json:"exp,omitempty"`
}

MeResult is returned by AuthCollection.Me. User is nil when there is no authenticated user for the request.

type MessageResult

type MessageResult struct {
	Message string `json:"message"`
}

MessageResult is a generic {"message": "..."} response, returned by operations that don't carry any other payload (Logout, Verify, Unlock, ForgotPassword).

type NoAuth

type NoAuth struct{}

NoAuth is a no-op Authenticator, used when the target PayloadCMS instance does not require authentication for the requested operations.

func (NoAuth) ApplyAuth

func (NoAuth) ApplyAuth(context.Context, *http.Request) error

ApplyAuth implements Authenticator and does nothing.

type Observer

type Observer interface {
	// OnRequest is called immediately before a request is sent.
	OnRequest(ctx context.Context, method, url string)
	// OnResponse is called once a request completes, successfully or not.
	// statusCode is 0 if no response was received at all (e.g. a network
	// error, DNS failure, or context cancellation).
	OnResponse(ctx context.Context, method, url string, statusCode int, duration time.Duration, err error)
}

Observer receives lifecycle notifications for every physical HTTP request the Client makes, including individual retry attempts, for logging, metrics or tracing.

type ObserverFunc

type ObserverFunc struct {
	Request  func(ctx context.Context, method, url string)
	Response func(ctx context.Context, method, url string, statusCode int, duration time.Duration, err error)
}

ObserverFunc adapts up to two plain functions into an Observer, so you don't need to declare a named type just to log requests. Either callback may be left nil to skip it.

func (ObserverFunc) OnRequest

func (f ObserverFunc) OnRequest(ctx context.Context, method, url string)

OnRequest implements Observer.

func (ObserverFunc) OnResponse

func (f ObserverFunc) OnResponse(ctx context.Context, method, url string, statusCode int, duration time.Duration, err error)

OnResponse implements Observer.

type Operator

type Operator string

Operator is a PayloadCMS query operator, as documented at https://payloadcms.com/docs/queries/overview#operators.

const (
	OpEquals           Operator = "equals"
	OpNotEquals        Operator = "not_equals"
	OpGreaterThan      Operator = "greater_than"
	OpGreaterThanEqual Operator = "greater_than_equal"
	OpLessThan         Operator = "less_than"
	OpLessThanEqual    Operator = "less_than_equal"
	OpLike             Operator = "like"
	OpContains         Operator = "contains"
	OpIn               Operator = "in"
	OpNotIn            Operator = "not_in"
	OpAll              Operator = "all"
	OpExists           Operator = "exists"
	OpNear             Operator = "near"
	OpWithin           Operator = "within"
	OpIntersects       Operator = "intersects"
)

type Option

type Option func(*Client)

Option configures a Client at construction time.

func WithAPIPrefix

func WithAPIPrefix(prefix string) Option

WithAPIPrefix overrides the default "/api" mount path. Use this if your PayloadCMS config sets a custom routes.api value.

func WithAuth

func WithAuth(a Authenticator) Option

WithAuth sets the Authenticator used to sign every outgoing request. It can also be changed later via Client.SetAuth.

func WithHTTPClient

func WithHTTPClient(hc *http.Client) Option

WithHTTPClient overrides the default http.Client (e.g. to customize transports or add tracing). Note that the default http.Client already carries a DefaultHTTPTimeout timeout; if you only want to change the timeout, WithTimeout is simpler than constructing a whole *http.Client.

func WithMaxGETURLLength

func WithMaxGETURLLength(n int) Option

WithMaxGETURLLength overrides DefaultMaxGETURLLength. Pass 0 to disable the method-override fallback entirely (GET requests will always be sent as GET, however long the resulting URL).

func WithObserver

func WithObserver(o Observer) Option

WithObserver registers an Observer to be notified of every outgoing HTTP request/response, including retries. There is no default Observer.

func WithRetry

func WithRetry(policy RetryPolicy) Option

WithRetry enables automatic retries, with exponential backoff and jitter, for idempotent requests (GET, HEAD, DELETE) that fail with a network-level error or a 429/500/502/503/504 response. There is no retrying by default; a zero-value Client never retries.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout overrides the timeout of the Client's http.Client (whether that's the built-in default or one supplied via WithHTTPClient), without requiring the caller to construct a whole *http.Client just to change this one field.

If used together with WithHTTPClient, apply WithTimeout after WithHTTPClient (options are applied in the order passed to New) if you want it to override that custom client's timeout too.

func WithUserAgent

func WithUserAgent(ua string) Option

WithUserAgent overrides the default User-Agent header sent with every request.

type PaginatedDocs

type PaginatedDocs[T any] struct {
	Docs          []T  `json:"docs"`
	TotalDocs     int  `json:"totalDocs"`
	Limit         int  `json:"limit"`
	TotalPages    int  `json:"totalPages"`
	Page          int  `json:"page"`
	PagingCounter int  `json:"pagingCounter"`
	HasPrevPage   bool `json:"hasPrevPage"`
	HasNextPage   bool `json:"hasNextPage"`
	PrevPage      *int `json:"prevPage"`
	NextPage      *int `json:"nextPage"`
}

PaginatedDocs is the shape returned by PayloadCMS's Find (list) operation.

type Preference

type Preference[T any] struct {
	ID             string `json:"-"`
	Key            string `json:"key"`
	User           string `json:"user"`
	UserCollection string `json:"userCollection"`
	Value          T      `json:"value"`
	CreatedAt      string `json:"createdAt"`
	UpdatedAt      string `json:"updatedAt"`
}

Preference wraps a single stored user preference document, as returned by GET /api/payload-preferences/{key}. Value holds whatever shape you pass to Preferences.Set, decoded into T.

See https://payloadcms.com/docs/admin/preferences.

func (Preference[T]) MarshalJSON

func (p Preference[T]) MarshalJSON() ([]byte, error)

MarshalJSON is the counterpart to UnmarshalJSON.

func (*Preference[T]) UnmarshalJSON

func (p *Preference[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts either "id" or "_id" for the preference document's own identifier.

type PreferenceSetResult

type PreferenceSetResult[T any] struct {
	Message string        `json:"message"`
	Doc     Preference[T] `json:"doc"`
}

PreferenceSetResult is returned by Preferences.Set, matching the documented {"message": ..., "doc": {...}} shape for POST /api/payload-preferences/{key}.

type Preferences

type Preferences[T any] struct {
	// contains filtered or unexported fields
}

Preferences is a generic, type-safe handle onto PayloadCMS's per-user Preferences API (GET/POST/DELETE /api/payload-preferences/{key}), scoped to whichever user the Client is currently authenticated as. T is the Go type of the preference's stored value.

func NewPreferences

func NewPreferences[T any](client *Client) *Preferences[T]

NewPreferences creates a Preferences handle for value type T.

func (*Preferences[T]) Delete

func (p *Preferences[T]) Delete(ctx context.Context, key string) (*MessageResult, error)

Delete removes the current user's preference stored under key.

func (*Preferences[T]) Get

func (p *Preferences[T]) Get(ctx context.Context, key string) (*Preference[T], error)

Get retrieves the current user's preference stored under key.

func (*Preferences[T]) Set

func (p *Preferences[T]) Set(ctx context.Context, key string, value T) (*PreferenceSetResult[T], error)

Set creates or updates the current user's preference stored under key.

type RefreshResult

type RefreshResult[T any] struct {
	Message        string `json:"message,omitempty"`
	User           T      `json:"user"`
	RefreshedToken string `json:"refreshedToken"`
	Exp            int64  `json:"exp"`
}

RefreshResult is returned by AuthCollection.Refresh, matching https://payloadcms.com/docs/authentication/operations#refresh.

type Refresher

type Refresher interface {
	Refresh(ctx context.Context) error
}

Refresher is an optional capability an Authenticator can implement: when a request comes back 401 Unauthorized, the Client calls Refresh once and, if it succeeds, retries the original request exactly once with the refreshed credentials. This is distinct from RetryPolicy (which handles transient network/5xx failures on idempotent methods only): a 401 means the request was rejected before anything happened server-side, so retrying after a refresh is safe for every HTTP method, including Create.

type RestoreVersionResult

type RestoreVersionResult[T any] struct {
	Doc     T
	Message string
}

RestoreVersionResult is returned by RestoreVersion. PayloadCMS's docs don't pin down a single response shape for this operation across versions of the framework, so this is decoded leniently: it accepts either the usual {"doc": ..., "message": ...} write-operation envelope, or a bare restored document.

type RetryPolicy

type RetryPolicy struct {
	// MaxRetries is the number of additional attempts made after the first
	// one fails. 0 disables retries.
	MaxRetries int
	// BaseDelay is the backoff delay before the first retry. Each
	// subsequent retry doubles it, up to MaxDelay. Defaults to 200ms if
	// zero.
	BaseDelay time.Duration
	// MaxDelay caps the backoff delay. Defaults to 2s if zero.
	MaxDelay time.Duration
}

RetryPolicy configures automatic retries for idempotent requests (GET, HEAD and DELETE). It intentionally never applies to POST/PATCH: Payload's Create endpoint is not idempotent, and blindly retrying it on a timeout could create duplicate documents.

func DefaultRetryPolicy

func DefaultRetryPolicy() RetryPolicy

DefaultRetryPolicy is a conservative preset: 3 retries, starting at 200ms and capped at 2s (with full jitter applied on top).

type UpdateResult

type UpdateResult[T any] struct {
	Doc     T        `json:"doc"`
	Message string   `json:"message"`
	Errors  []APIErr `json:"errors,omitempty"`
}

UpdateResult is the shape returned by PayloadCMS's Update-by-ID operation.

type UploadFile

type UploadFile struct {
	// Reader provides the file's bytes. If it also implements io.Closer,
	// it is closed automatically once the request completes.
	Reader io.Reader

	// Filename is sent as the uploaded file's name. Its extension is also
	// used to infer ContentType when ContentType is left empty.
	Filename string

	// ContentType overrides the auto-detected MIME type sent in the
	// multipart part's Content-Type header. Optional: if empty, it is
	// derived from Filename's extension, falling back to
	// "application/octet-stream".
	ContentType string
}

UploadFile describes the binary content to send when creating or re-uploading a document in an upload-enabled PayloadCMS collection (e.g. a "media" collection), as documented at https://payloadcms.com/docs/upload/overview#uploading-files.

func NewUploadFileFromPath

func NewUploadFileFromPath(path string) (UploadFile, error)

NewUploadFileFromPath opens the file at path and returns an UploadFile ready to be passed to Collection.CreateWithFile / UpdateWithFile. The underlying *os.File is closed automatically once the request completes.

type Version

type Version[T any] struct {
	ID        string `json:"-"`
	Parent    string `json:"parent,omitempty"`
	Autosave  bool   `json:"autosave"`
	Version   T      `json:"version"`
	CreatedAt string `json:"createdAt"`
	UpdatedAt string `json:"updatedAt"`
}

Version wraps a single stored version of a document (or Global), as returned by the {collection}/versions and globals/{slug}/versions endpoints. See https://payloadcms.com/docs/versions/overview.

Parent is only populated for collection versions; Global versions don't have one, since each Global keeps its own dedicated versions collection.

func (Version[T]) MarshalJSON

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

MarshalJSON is the counterpart to UnmarshalJSON: it re-adds "id" (omitted by the struct's own "-" tag, which exists solely to avoid colliding with this field during unmarshaling) so that Version[T] round-trips correctly through JSON.

func (*Version[T]) UnmarshalJSON

func (v *Version[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts either "id" (Payload's usual REST/GraphQL convention) or "_id" (seen in some internal/DB-level examples in Payload's own docs) for the version's own identifier.

type Where

type Where map[string]any

Where represents a (possibly nested) PayloadCMS filter condition tree. It mirrors the shape of Payload's own `Where` type, so it can be built either through the helper constructors below (Equals, GreaterThan, And, Or, ...) or by hand, e.g.: gopcms.Where{"color": gopcms.Where{"equals": "mint"}}

func All

func All(field string, values ...any) Where

All builds an "all" condition (MongoDB adapter only): the field's array value must contain every value provided.

func And

func And(conditions ...Where) Where

And combines multiple conditions with AND logic. Conditions can be arbitrarily nested with Or.

Example

ExampleAnd shows how conditional filters combine with And/Or, nested as deeply as needed, mirroring PayloadCMS's own Where query language.

package main

import (
	"github.com/TaiBomb/gopcms"
)

func main() {
	where := gopcms.Or(
		gopcms.Equals("color", "mint"),
		gopcms.And(
			gopcms.Equals("color", "white"),
			gopcms.Equals("featured", false),
		),
	)
	_ = where // pass this as FindOptions.Where / CountOptions.Where
}

func Contains

func Contains(field string, value any) Where

Contains builds a "contains" (case-insensitive substring) condition.

func Equals

func Equals(field string, value any) Where

Equals builds an "equals" condition.

func Exists

func Exists(field string, exists bool) Where

Exists builds an "exists" condition.

func Field

func Field(field string, op Operator, value any) Where

Field builds a single "field operator value" condition, e.g. Field("age", OpGreaterThan, 18) -> where[age][greater_than]=18.

field may use dot notation to reach nested / related properties, as described at https://payloadcms.com/docs/queries/overview#nested-properties.

func GreaterThan

func GreaterThan(field string, value any) Where

GreaterThan builds a "greater_than" condition.

func GreaterThanEqual

func GreaterThanEqual(field string, value any) Where

GreaterThanEqual builds a "greater_than_equal" condition.

func In

func In(field string, values ...any) Where

In builds an "in" condition; values is the set of acceptable values.

func Intersects

func Intersects(field string, geoJSON any) Where

Intersects builds an "intersects" condition for Point fields.

func LessThan

func LessThan(field string, value any) Where

LessThan builds a "less_than" condition.

func LessThanEqual

func LessThanEqual(field string, value any) Where

LessThanEqual builds a "less_than_equal" condition.

func Like

func Like(field string, value any) Where

Like builds a "like" (case-insensitive, unordered word match) condition.

func Near

func Near(field string, longitude, latitude, maxDistance, minDistance float64) Where

Near builds a "near" condition for Point fields: longitude, latitude and an optional maxDistance/minDistance in meters (pass 0 to omit either).

func NotEquals

func NotEquals(field string, value any) Where

NotEquals builds a "not_equals" condition.

func NotIn

func NotIn(field string, values ...any) Where

NotIn builds a "not_in" condition.

func Or

func Or(conditions ...Where) Where

Or combines multiple conditions with OR logic. Conditions can be arbitrarily nested with And.

func Within

func Within(field string, geoJSON any) Where

Within builds a "within" condition for Point fields, given a GeoJSON geometry (as a map, matching Payload's documented shape).

Jump to

Keyboard shortcuts

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