Documentation
¶
Overview ¶
Package hmc provides types for building HATEOAS-driven REST APIs with progressive enhancement.
Each type represents a hypermedia control—a semantic element that guides client state transitions. These controls can be serialized as JSON, XML, or wrapped in HTML templates depending on the client's capabilities.
Philosophy ¶
Traditional REST APIs serve data (JSON) and leave state transitions to out-of-band documentation. HATEOAS APIs serve hypermedia—data enriched with the controls needed to interact with it. This library provides the building blocks for those controls.
The types in hmc are deliberately minimal, focusing on the semantic layer rather than presentation. They describe WHAT actions are available and HOW to invoke them, not how they should be styled or rendered.
Progressive Enhancement ¶
The same endpoint can serve multiple representations:
- JSON: Machine-readable, suitable for scripts and traditional API clients
- XML: Human-readable structure for CLI tools (curl, HTTPie + xmllint)
- HTML: Browser-ready interfaces when wrapped with your templates
This enables a "write once, serve many" approach where a single handler can satisfy browsers, CLIs, and programmatic clients through content negotiation.
Usage ¶
Types are designed to be embedded in your domain structs:
type LoginPage struct {
LoginForm hmc.Form[struct {
Username hmc.Input
Password hmc.Input
Submit hmc.Submit
}]
RegisterLink hmc.Link
}
Marshal to JSON for API clients, XML for CLI tools, or wrap in HTML templates for browsers. Examples at ./examples/templates.
Input validation is minimal and extensible—Validate() checks Required and MinLength, matching basic browser behavior. Extend by inspecting Input.Value and setting Input.Error for domain-specific rules.
Pairs Well With ¶
This library pairs naturally with github.com/Teajey/rsvp, which provides HTTP handlers with ergonomic content negotiation, making it easy to serve the same semantic data in multiple formats based on Accept headers.
What This Is Not ¶
This is not a complete HTML generation framework. You bring your own templates for presentation (you should use the examples as a starting point). This is not a client-side form library—it's server-side semantics. This is not a validation framework—it provides minimal checks and extension points for your domain rules.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Form ¶
Form is analogous to HTML's <form> which represents a state transition that requires input from the client. It describes what data is needed, how it should be submitted, and where it should be sent.
Elements should contain a struct representing, and elements semantically related to the form, which would usually be Input, Select, Map, Link, etc. but might also be something like `Error string` or `Warning string` fields.
func (Form[T]) MarshalXML ¶
type Input ¶
type Input struct {
Label string
Type string
Name string
Required bool
Value string
Error string
MinLength uint
MaxLength uint
Step float32
Min string
Max string
}
Input describes a piece of data the server needs from the client, including validation requirements.
It is analogous to HTML's <input> and <textarea>.
IMPORTANT: Some fields are mutually-irrelevant; such as Options and MinLength, but they are both kept in this struct for simplicity. It is not an error to have them both set at the same time, but it is semantically incorrect and may cause confusion.
func (*Input) ExtractFormValue ¶
ValueFromUrlValues will searching for the Input's value under p.Name, setting p.Value.
The found value is deleted from form.
func (Input) MarshalJSON ¶
func (Input) MarshalXML ¶
func (*Input) Validate ¶
func (p *Input) Validate()
Validate performs some basic checks on the value of the input according to its settings.
[Input.Required], [Input.Max], [Input.Min], [Input.MaxLength], and [Input.MinLength] are checked, in that order. Similar to the minimal checks that a browser would make for equivalent HTML.
This functionality can be extended with more bespoke validation by checking fields and setting the [Input.Error] field accordingly.
type Link ¶
Link represents a state transition that requires no input—a simple navigation or action trigger.
func (Link) MarshalXML ¶
type Map ¶
type Map struct {
Label string `json:"label"`
Name string `json:"name"`
Entries map[string][]string `json:"entries"`
Error string `json:"error,omitempty"`
}
func (*Map) ExtractFormValue ¶
func (Map) MarshalXML ¶
type Namespace ¶
type Namespace struct {
HcXmlns string `xml:"xmlns:c,attr" json:"-"`
Docs xml.Comment `xml:",comment" json:"-"`
}
Namespace should be embedded in the top-level element to provide context about what the hyper control elements are.
SetNamespace should be used to populate the values to their default.
func SetNamespace ¶
func SetNamespace() Namespace
SetNamespace provides a default setting for the Namespace struct.
type Option ¶
type Option struct {
Label string `json:"label,omitempty"`
Value string `json:"value"`
Selected bool `json:"selected,omitempty"`
Disabled bool `json:"disabled,omitempty"`
}
func (Option) MarshalXML ¶
type Select ¶
type Select struct {
Multiple bool `json:"multiple,omitempty"`
Label string `json:"label"`
Name string `json:"name"`
Required bool `json:"required,omitempty"`
Options []Option `json:"options"`
Error string `json:"error,omitempty"`
}