Help us shape the future of Go! Take the 2026 Go Developer Survey

formlookup

package
v0.21.0 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2026 License: AGPL-3.0 Imports: 23 Imported by: 0

Documentation

Overview

Package formlookup serves a task form's remote data sources: a person types into a directory field and sees the first matching entries of a directory the server never copies (ADR-0473).

The form says what may be searched; this package enforces what the person may access; the Worker performs the search; the browser holds one page; and the durable workflow records only the value the person finally submits.

**What the request may say** is what a person can know: the term they typed, what they picked in the form's other fields, a cursor this server handed them, and a page size no larger than the field's. Which Worker, which tenant, which resource, which properties are searched and returned — all of that is read from the task's stored form and from the provider registry, and a request naming any of it is refused.

**This area owns no state**, like formgen: its collaborators are the server's and each observes the single writer itself (I3). What it does hold — a query waiting for a Worker Instance — waits on the request's own goroutine, with the run loop free, and is never written anywhere: nothing here reaches the log, the processor or recovery.

Index

Constants

View Source
const (
	// VerifyLookup looks the value up once more, under the field's filters.
	VerifyLookup = "lookup"
	// VerifyFormat checks only that the value has the shape of one.
	VerifyFormat = "format"
)

The ways a submitted value is checked before its task completes.

View Source
const DataSourceMember = "atlasDataSource"

DataSourceMember is the component member that makes a select a directory field.

View Source
const DefaultTimeout = 8 * time.Second

DefaultTimeout is what a person waits for at most. Graph answers a filtered page in well under a second; a lookup still waiting after this is not going to be useful.

View Source
const Version = 1

Version is the one version of the block this server reads. A form written for a newer one is refused at save with that reason, rather than half-understood.

Variables

View Source
var (
	ErrNoTask    = errors.New("formlookup: no open task with that key")
	ErrForbidden = errors.New("formlookup: the caller may not work on this task")
)

The task collaborator's two refusals.

View Source
var Codes = []string{
	"forbidden", "not_found", "invalid_query", "invalid_cursor", "invalid_configuration",
	"rate_limited", "worker_unavailable", "worker_busy", "provider_throttled",
	"provider_unavailable", "provider_refused", "timeout",
}

Codes are the machine-readable codes a lookup or a refused completion answers with, beside the human-readable error. A client branches on these and words them itself; the console's catalogue carries a message for each (remote.error.<code>), which a test holds it to.

Functions

func Check

func Check(schema []byte) error

Check is what a form save asks: may this schema be stored?

Types

type Config

type Config struct {
	// Task authorizes the caller against a task — the question task completion asks,
	// ADR-0317 — and returns its form. ErrNoTask and ErrForbidden are its refusals.
	Task func(r *http.Request, key uint64) (Task, error)
	// Worker resolves a Worker by name from the Worker store.
	Worker func(name string) (Worker, bool, error)
	// Workers lists the Workers a model author may pick, for the editor.
	Workers func(r *http.Request) ([]Worker, error)
	// Ask puts a query to a Worker Instance and waits for its answer.
	Ask func(ctx context.Context, jobType, connector string, q lookup.Query, timeout time.Duration) (lookup.Page, error)
	// Allow is the per-person rate limit.
	Allow func(key string) bool
	// Principal names the caller, for the rate limit and for the cursor a page is
	// continued with. Empty when the server runs without authentication.
	Principal func(r *http.Request) string
	// Timeout bounds one query.
	Timeout time.Duration
	// MaxBody bounds a request's body: the server's Request budget.
	MaxBody int64
}

Config is the server's half of this area.

type Field

type Field struct {
	Key      string
	Label    string
	Required bool
	// Conditional is set when form-js may hide the field. The server cannot evaluate
	// form-js's condition, so it does not insist on a value a hidden field never sends.
	Conditional bool
	// Disabled fields are not submitted by form-js, and not checked.
	Disabled bool
	Source   Source
	Provider Provider
}

Field is one directory field of a form, checked.

func (Field) ActiveOnly

func (f Field) ActiveOnly() bool

ActiveOnly reports whether disabled records are left out.

func (Field) DescriptionProperty

func (f Field) DescriptionProperty() string

DescriptionProperty is what the line under an option's label reads.

func (Field) LabelProperty

func (f Field) LabelProperty() string

LabelProperty is what an option's label reads.

func (Field) MinSearchLength

func (f Field) MinSearchLength() int

MinSearchLength is how many characters a term needs.

func (Field) PageSize

func (f Field) PageSize() int

PageSize is how many options one answer carries.

func (Field) Properties

func (f Field) Properties() []string

Properties are everything a lookup for this field reads, and nothing more: the value, what the option shows, and the fallback for a record that leaves either empty.

func (Field) SearchFields

func (f Field) SearchFields() []string

SearchFields are the properties a term is a prefix of.

func (Field) Verify

func (f Field) Verify() string

Verify is how a submitted value is checked.

type Filter

type Filter struct {
	Property string `json:"property"`
	Field    string `json:"field,omitempty"`
	Value    string `json:"value,omitempty"`
	// Required makes a bound filter a precondition: no search runs until its field has
	// a value. Without it, an empty field leaves the search unnarrowed.
	Required bool `json:"required,omitempty"`
}

Filter narrows a search by equality. Field binds it to the value another field of the same form holds; Value fixes it, whatever a request says.

type Form

type Form struct {
	Fields []Field
	// contains filtered or unexported fields
}

Form is what a schema says about its directory fields and about the fields they may be bound to.

func Parse

func Parse(schema []byte) (*Form, error)

Parse reads a form-js schema's directory fields and checks every one of them against what this server can honour. A schema without any is every form that existed before them and parses to none; a malformed atlasDataSource is refused with the field and the reason.

func (*Form) Field

func (f *Form) Field(key string) (Field, bool)

Field finds the directory field with this key.

func (*Form) StaticOptions

func (f *Form) StaticOptions(key string) ([]string, bool)

StaticOptions are the option values a field fixes in the form itself — a select's `values` — and false when it has none (no such field, or options from a variable or an expression, which the server cannot know).

type Item

type Item struct {
	// Value is what the form submits: the record's identifier.
	Value string `json:"value"`
	// Label is what a person reads; Description the line under it.
	Label       string            `json:"label"`
	Description string            `json:"description,omitempty"`
	Details     map[string]string `json:"details,omitempty"`
}

Item is one option as the form shows it.

type Option

type Option struct {
	Label       string   `json:"label,omitempty"`
	Description string   `json:"description,omitempty"`
	Details     []string `json:"details,omitempty"`
}

Option says what a result shows: the label a person reads, the line under it, and up to four details beside it. The value is always the source's own identifier.

type Provider

type Provider struct {
	// WorkerType is the Worker Type a form's Worker must be of — the kind of its
	// Console record ("entra").
	WorkerType string `json:"workerType"`
	// Resource is what is searched, in the Worker Type's vocabulary ("users").
	Resource string `json:"resource"`
	// JobType routes the query: it reaches Worker Instances serving this job type.
	JobType string `json:"-"`
	// Label names the source to a model author.
	Label string `json:"label"`
	// ValueProperty identifies a record; it is what a form submits.
	ValueProperty string   `json:"valueProperty"`
	Searchable    []string `json:"searchable"`
	Filterable    []string `json:"filterable"`
	Readable      []string `json:"readable"`
	// DefaultLabel and DefaultDescription are what an option shows when the form
	// names nothing; Fallback stands in for either when a record leaves it empty — a
	// user without a mailbox still has a user principal name.
	DefaultLabel       string `json:"defaultLabel"`
	DefaultDescription string `json:"defaultDescription"`
	Fallback           string `json:"fallback,omitempty"`
	// ValueFormat says in words what a value looks like, for an error message.
	ValueFormat string `json:"valueFormat"`
	// contains filtered or unexported fields
}

Provider is one remote data source a form may name: a resource of a Worker Type, what of it may be searched, filtered and shown, and how its records are told apart.

It is the server's half of a rule the Worker Type keeps too. The lists come from the Worker Type's own table (for Entra, entra.LookupResources), so the server refuses at save and at query time exactly what the Worker would refuse at answer time, and the two cannot drift: there is one table, and this is a view of it.

func ProviderFor

func ProviderFor(workerType, resource string) (Provider, bool)

ProviderFor finds the source a form names.

func Providers

func Providers() []Provider

Providers lists the remote data sources this server offers.

func (Provider) Check

func (p Provider) Check(q lookup.Query) error

Check holds a query to the Worker Type's own rules, before it is sent.

func (Provider) ValidValue

func (p Provider) ValidValue(v string) bool

ValidValue reports whether v has the shape of a value of this source.

type Service

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

Service serves remote data sources. Build it with New.

func New

func New(cfg Config) *Service

New builds the service.

func (*Service) CheckSubmission

func (s *Service) CheckSubmission(ctx context.Context, schema []byte, vars map[string]any) *SubmissionError

CheckSubmission checks every directory field of schema against the variables a completion submits, in the order the form shows them, and returns the first refusal. A form without a directory field is not checked at all, so every form that existed before them completes exactly as it did.

func (*Service) HandleQuery

func (s *Service) HandleQuery(w http.ResponseWriter, r *http.Request)

HandleQuery is POST /api/v1/tasks/{key}/form-data/{field}/query.

func (*Service) HandleSources

func (s *Service) HandleSources(w http.ResponseWriter, r *http.Request)

HandleSources is GET /api/v1/form-data/sources: what a model author can configure — the sources this server offers, and the Workers a field can name, each saying whether it lets forms search it.

type Source

type Source struct {
	Version      int      `json:"version"`
	WorkerType   string   `json:"workerType"`
	Worker       string   `json:"worker"`
	Resource     string   `json:"resource"`
	SearchFields []string `json:"searchFields,omitempty"`
	Filters      []Filter `json:"filters,omitempty"`
	Option       Option   `json:"option,omitempty"`
	PageSize     int      `json:"pageSize,omitempty"`
	// MinSearchLength is how many characters a term needs before it is searched; 0
	// lists what the filters admit without one. Absent means 2.
	MinSearchLength *int `json:"minSearchLength,omitempty"`
	// ActiveOnly leaves disabled accounts out. Absent means true: a person picked for
	// a process is normally somebody who can still sign in, and a leaver process that
	// wants the disabled ones says so.
	ActiveOnly *bool  `json:"activeOnly,omitempty"`
	Verify     string `json:"verify,omitempty"`
}

Source is the atlasDataSource block as a form states it.

type SubmissionError

type SubmissionError struct {
	Status     int
	Code       string
	Message    string
	RetryAfter int
}

SubmissionError is a completion refused for a directory field's value.

func (*SubmissionError) Error

func (e *SubmissionError) Error() string

func (*SubmissionError) Write

func (e *SubmissionError) Write(w http.ResponseWriter)

Write answers the refused completion in the lookup's error shape.

type Task

type Task struct {
	Schema []byte
}

Task is what a lookup needs of the task it is made from: its form, as the form store holds it now.

type Worker

type Worker struct {
	Name       string `json:"name"`
	WorkerType string `json:"workerType"`
	Enabled    bool   `json:"enabled"`
	// FormLookups is the Worker's own switch: its editors decide whether a form may
	// search through its credential (ADR-0205). Seeing a form, or editing one, is not
	// that permission.
	FormLookups bool `json:"formLookups"`
}

Worker is a configured Worker as this area judges it. No endpoint and nowhere to put a credential.

Jump to

Keyboard shortcuts

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