pbclient

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Nov 21, 2025 License: MIT Imports: 14 Imported by: 0

README

PocketBase Client

Go client library for PocketBase with automatic admin auth, generic repository helpers, and a simple KV store built on collections.

Installation

go get github.com/eqr/pbclient

Quick Start

package main

import (
	"context"
	"log"

	"github.com/eqr/pbclient"
)

type Todo struct {
	ID    string `json:"id"`
	Title string `json:"title"`
	Done  bool   `json:"done"`
}

func main() {
	client, err := pbclient.NewClient(
		"https://your-pocketbase-host",
		"admin@example.com",
		"super-secret",
	)
	if err != nil {
		log.Fatal(err)
	}

	repo := pbclient.NewRepository[Todo](client, "todos")

	ctx := context.Background()

	created, err := repo.Create(ctx, Todo{Title: "try pbclient"})
	if err != nil {
		log.Fatal(err)
	}

	item, err := repo.Get(ctx, created.ID)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("got todo: %+v", item)
}

Client Options

  • WithHTTPClient(*http.Client): reuse your own transport (e.g., tracing, custom TLS).
  • WithTimeout(time.Duration): set HTTP timeout.
  • WithRetry(maxRetries, backoff): retry 429/network errors with exponential backoff.
  • WithLogger(*slog.Logger): structured logging for auth and retries.
  • WithAuthToken(token, expires): seed an existing auth token instead of logging in.

Repository Usage

repo := pbclient.NewRepository[Todo](client, "todos")

// List with filters, sorting, and field selection
todos, err := repo.List(ctx, pbclient.ListOptions{
	Page:   1,
	PerPage: 20,
	Filter: pbclient.And(pbclient.Eq("done", "false"), pbclient.Gt("priority", "3")),
	Sort:   "-created",
	Fields: []string{"id", "title", "done"},
})

// Update an item
updated, err := repo.Update(ctx, created.ID, Todo{Title: "updated title", Done: true})

KV Store Usage

kv := pbclient.NewKVStore(client, "kv_store") // collection defaults to "kv_store"

_ = kv.Set(ctx, "feature_flag", map[string]any{"name": "beta", "enabled": true})

var flag map[string]any
_ = kv.Get(ctx, "feature_flag", &flag)

exists, _ := kv.Exists(ctx, "feature_flag")
keys, _ := kv.List(ctx, "feature_")
_ = kv.Delete(ctx, "feature_flag")

Filters

Helpers for PocketBase filter strings:

  • Eq/Neq/Gt/Gte/Lt/Lte
  • And/Or to combine conditions

Example: pbclient.And(pbclient.Eq("status", "active"), pbclient.Gt("score", "10"))

Error Handling

Common HTTP statuses map to sentinel errors (ErrBadRequest, ErrUnauthorized, ErrForbidden, ErrNotFound, ErrConflict, ErrValidation, ErrRateLimited, ErrServer). Other statuses return *HTTPError with status/message.

Thread Safety

Client is safe for concurrent use; token access is locked and retries respect context cancellation. Repository and KV helpers share the same client and rely on PocketBase for atomicity.

Integration Tests

An in-process PocketBase integration test is provided (pocketbase_integration_test.go, build tag integration). Run with:

go test -tags=integration ./...

It reuses PocketBase's bundled test data under GOPATH.

Migrations

The migrations package ships an HTTP-based runner. By default it auto-creates a pb_migrations collection with authenticated-only rules and records applied migration names/timestamps. Example:

runner := migrations.NewRunner(client) // auto-creates pb_migrations with auth-only access rules
_ = runner.Register(migrations.MyFirstMigration{})
_ = runner.Run(ctx)

pending, _ := runner.Pending(ctx)
_ = runner.Down(ctx, 1) // roll back latest

To disable auto-creation and require a pre-provisioned collection, pass migrations.WithAutoCreate(false); the runner will return ErrCollectionNotFound if the collection is missing.

License

MIT – see LICENSE for details.

Release Notes (v0.0.1)

  • Client with lazy admin auth, retries, and token refresh.
  • Generic repository with CRUD, filtering, pagination helpers.
  • KV store abstraction on top of collections.
  • Filter builders (Eq, Gt, And, etc.).
  • PocketBase-aware error mapping.
  • Extensive unit tests and an optional integration test.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrBadRequest   = errors.New("bad request")
	ErrUnauthorized = errors.New("unauthorized")
	ErrForbidden    = errors.New("forbidden")
	ErrNotFound     = errors.New("not found")
	ErrConflict     = errors.New("conflict")
	ErrValidation   = errors.New("validation failed")
	ErrRateLimited  = errors.New("rate limited")
	ErrServer       = errors.New("server error")
)

Sentinel errors returned for common HTTP statuses.

Functions

func And

func And(filters ...string) string

And joins filters with logical AND, skipping empty entries.

func Eq

func Eq(field, value string) string

Eq builds an equality filter: field='value'.

func Gt

func Gt(field, value string) string

Gt builds a greater-than filter: field>value.

func Gte

func Gte(field, value string) string

Gte builds a greater-than-or-equal filter: field>=value.

func Lt

func Lt(field, value string) string

Lt builds a less-than filter: field<value.

func Lte

func Lte(field, value string) string

Lte builds a less-than-or-equal filter: field<=value.

func Neq

func Neq(field, value string) string

Neq builds a not-equal filter: field!='value'.

func Or

func Or(filters ...string) string

Or joins filters with logical OR, skipping empty entries.

Types

type Client

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

Client provides authenticated HTTP access to PocketBase. It is safe for concurrent use.

func NewClient

func NewClient(baseURL, adminEmail, adminPassword string, opts ...ClientOption) (*Client, error)

NewClient constructs a PocketBase client without performing authentication. Use ClientOptions to set timeouts, retries, logging, or custom transports.

func (*Client) Do added in v0.0.2

func (c *Client) Do(ctx context.Context, method, path string, body io.Reader) (*http.Response, error)

Do executes an authenticated HTTP request with retries. Callers must close the returned response body.

type ClientOption

type ClientOption func(*Client)

ClientOption configures optional Client settings.

func WithAuthToken added in v0.0.2

func WithAuthToken(token string, expires time.Time) ClientOption

WithAuthToken seeds the client with an existing authentication token and optional expiry. If token is empty, this option does nothing.

func WithHTTPClient

func WithHTTPClient(client *http.Client) ClientOption

WithHTTPClient overrides the default http.Client.

func WithLogger

func WithLogger(logger *slog.Logger) ClientOption

WithLogger attaches a logger used for debug information.

func WithRetry

func WithRetry(maxRetries int, backoff time.Duration) ClientOption

WithRetry sets the maximum number of retries for transient errors and the base backoff. Retries apply to network errors and HTTP 429 responses.

func WithTimeout

func WithTimeout(timeout time.Duration) ClientOption

WithTimeout sets the HTTP client timeout.

type HTTPError

type HTTPError struct {
	Status  int
	Message string
}

HTTPError captures the status and response message for non-2xx responses.

func (*HTTPError) Error

func (e *HTTPError) Error() string

type KVStore

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

KVStore offers simple key-value helpers backed by PocketBase.

func NewKVStore

func NewKVStore(client *Client, collection string) *KVStore

NewKVStore creates a key-value store backed by the provided collection. If collection is empty, a default "kv_store" collection is used.

func (*KVStore) Delete

func (s *KVStore) Delete(ctx context.Context, key string) error

Delete removes a key. It is idempotent and returns nil if the key does not exist.

func (*KVStore) Exists

func (s *KVStore) Exists(ctx context.Context, key string) (bool, error)

Exists returns true if a key exists.

func (*KVStore) Get

func (s *KVStore) Get(ctx context.Context, key string, dest interface{}) error

Get fetches a value for the given key into dest.

func (*KVStore) List

func (s *KVStore) List(ctx context.Context, prefix string) ([]string, error)

List returns all keys, optionally filtered by prefix.

func (*KVStore) Set

func (s *KVStore) Set(ctx context.Context, key string, value interface{}) error

Set inserts or overwrites a value for the given key.

type ListOptions

type ListOptions struct {
	Page    int
	PerPage int
	Filter  string
	Sort    string
	Fields  []string
}

ListOptions describes pagination and filtering options for list calls.

type ListResult

type ListResult[T any] struct {
	Items      []T
	Page       int
	PerPage    int
	TotalItems int
	TotalPages int
}

ListResult contains a page of items with pagination metadata.

type Repository

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

Repository exposes CRUD helpers for PocketBase collections.

func NewRepository

func NewRepository[T any](client *Client, collection string) *Repository[T]

NewRepository creates a repository bound to a PocketBase collection.

func (*Repository[T]) Create

func (r *Repository[T]) Create(ctx context.Context, record T) (*T, error)

Create inserts a new record.

func (*Repository[T]) Delete

func (r *Repository[T]) Delete(ctx context.Context, id string) error

Delete removes a record by ID.

func (*Repository[T]) Get

func (r *Repository[T]) Get(ctx context.Context, id string) (*T, error)

Get fetches a single record by ID.

func (*Repository[T]) List

func (r *Repository[T]) List(ctx context.Context, opts ListOptions) (*ListResult[T], error)

List returns a page of records using the provided options.

func (*Repository[T]) Update

func (r *Repository[T]) Update(ctx context.Context, id string, record T) (*T, error)

Update patches an existing record.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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