widget

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 25, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package widget is the example vertical slice. A resource lives in one package: its SQL (queries.sql), persistence (store.go), business logic (service.go), and HTTP handlers (handler.go). The day-2 generator stamps new resources in this shape (see cmd/forge).

Index

Constants

View Source
const PermissionWrite = "widgets:write"

PermissionWrite is required to create, replace, or delete a widget.

Variables

View Source
var (
	ErrNotFound  = errors.New("widget not found")
	ErrForbidden = errors.New("forbidden")
	// ErrIdempotencyReserved means another request already claimed the key; the
	// caller should replay the stored response.
	ErrIdempotencyReserved = errors.New("idempotency key already reserved")
)

Functions

This section is empty.

Types

type Handler

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

Handler adapts HTTP to the widget service. It implements the generated api.ServerInterface for the widget operations.

func NewHandler

func NewHandler(service *Service, idem *idempotency.Store) *Handler

func (*Handler) CreateWidget

func (h *Handler) CreateWidget(w http.ResponseWriter, r *http.Request, params api.CreateWidgetParams)

func (*Handler) DeleteWidget

func (h *Handler) DeleteWidget(w http.ResponseWriter, r *http.Request, id api.WidgetID)

func (*Handler) GetWidget

func (h *Handler) GetWidget(w http.ResponseWriter, r *http.Request, id api.WidgetID)

func (*Handler) ListWidgets

func (h *Handler) ListWidgets(w http.ResponseWriter, r *http.Request, params api.ListWidgetsParams)

func (*Handler) UpdateWidget

func (h *Handler) UpdateWidget(w http.ResponseWriter, r *http.Request, id api.WidgetID)

type IdempotencyClaim

type IdempotencyClaim struct {
	Key  string
	Hash string
	TTL  time.Duration
}

IdempotencyClaim ties a create to a client-supplied Idempotency-Key. When set, the key is inserted in the same transaction as the widget, so a concurrent retry that loses the race is rolled back rather than creating a duplicate.

type Input

type Input struct {
	Name        string
	Description string
	Status      string
}

Input is the validated, transport-independent data needed to create or replace a widget.

type Repository

type Repository interface {
	Create(ctx context.Context, in Input, claim *IdempotencyClaim) (db.Widget, error)
	Get(ctx context.Context, id uuid.UUID) (db.Widget, error)
	List(ctx context.Context, limit, offset int32) ([]db.Widget, int64, error)
	Update(ctx context.Context, id uuid.UUID, in Input) (db.Widget, error)
	Delete(ctx context.Context, id uuid.UUID) error
}

Repository is the persistence seam. Swap the implementation to change the datastore without touching the service or handler.

func NewRepository

func NewRepository(pool *pgxpool.Pool) Repository

type Service

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

Service holds the business rules for widgets, including authorization. It depends on the Repository interface, so it is unit-testable without a database.

func NewService

func NewService(repo Repository, logger *slog.Logger) *Service

func (*Service) Create

func (s *Service) Create(ctx context.Context, actor auth.Principal, in Input, claim *IdempotencyClaim) (db.Widget, error)

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, actor auth.Principal, id uuid.UUID) error

func (*Service) Get

func (s *Service) Get(ctx context.Context, id uuid.UUID) (db.Widget, error)

func (*Service) List

func (s *Service) List(ctx context.Context, limit, offset int32) ([]db.Widget, int64, error)

func (*Service) Update

func (s *Service) Update(ctx context.Context, actor auth.Principal, id uuid.UUID, in Input) (db.Widget, error)

Jump to

Keyboard shortcuts

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