Required combinations
A GroupConstraint item inside a Schema declares a cardinality constraint across a named group of properties — "exactly one of these must be present", "at least one", "at most one".
When to use
Use a group constraint when you have mutually exclusive or collectively required properties. For example:
- A user must authenticate with exactly one of
password,oauth-token, orsaml-assertion. - A contact must have at least one of
email,phone, oraddress. - A payment must have at most one of
credit-cardorbank-account.
Syntax
A GroupConstraint is nested within a Schema via itemprop="constraint".
<div itemprop="constraint" itemscope itemtype="https://schema.host/GroupConstraint">
<meta itemprop="group" content="auth-method">
<meta itemprop="cardinality" content="1..1">
</div>
The properties that belong to the group are declared individually using the group property on each Property definition:
<div itemprop="property" itemscope itemtype="https://pagelove.org/Property">
<meta itemprop="name" content="password">
<meta itemprop="type" content="https://schema.host/Text">
<meta itemprop="cardinality" content="0..1">
<meta itemprop="group" content="auth-method">
</div>
<div itemprop="property" itemscope itemtype="https://pagelove.org/Property">
<meta itemprop="name" content="oauth-token">
<meta itemprop="type" content="https://schema.host/Text">
<meta itemprop="cardinality" content="0..1">
<meta itemprop="group" content="auth-method">
</div>
Properties
| Property | Type | Cardinality | Description |
|---|---|---|---|
group |
Text | 1..1 | The group name. Must match group values on Property items. Required. |
cardinality |
Cardinal | 0..1 | How many properties from the group must be present. Default 0..n. |
group (required)
The name of the group this constraint applies to. This must match the group property values declared on the Property items that belong to the group.
A GroupConstraint without a group property (or with an empty group name) is silently skipped.
cardinality (optional)
The cardinality constraint applied to the count of present properties in the group. "Present" means the property has at least one [itemprop] element in the item.
| Value | Meaning |
|---|---|
0..n |
Any number of group properties may be present (default, no constraint) |
0..1 |
At most one property from the group may be present |
1..1 |
Exactly one property from the group must be present |
1..n |
At least one property from the group must be present |
If omitted, defaults to 0..n (no constraint).
How groups are assembled
Group membership is declared on individual Property items via the group property. A property can belong to multiple groups. The system collects all properties across the entire inheritance chain that share the same group name and counts how many are present on a given item.
For example, given properties password (group: auth-method), oauth-token (group: auth-method), and saml-assertion (group: auth-method), a group constraint with cardinality: 1..1 requires exactly one of these three to have at least one value.
Inheritance behaviour
Group constraints follow the same inheritance model as other schema features:
- Property group membership is additive across the chain. A child can add new properties to a group defined in the parent.
- Constraint cardinality uses child-overrides-parent. If the parent declares
auth-methodas1..1and the child declaresauth-methodas1..n, the child's1..ntakes effect for items of the child type. - Group constraints from the parent apply to the child unless explicitly overridden.
Examples
Exactly one authentication method
<div itemscope itemtype="https://pagelove.org/Schema">
<meta itemprop="type" content="https://example.com/UserAuth">
<meta itemprop="name" content="UserAuth">
<div itemprop="property" itemscope itemtype="https://pagelove.org/Property">
<meta itemprop="name" content="password">
<meta itemprop="type" content="https://schema.host/Text">
<meta itemprop="cardinality" content="0..1">
<meta itemprop="group" content="auth-method">
</div>
<div itemprop="property" itemscope itemtype="https://pagelove.org/Property">
<meta itemprop="name" content="oauth-token">
<meta itemprop="type" content="https://schema.host/Text">
<meta itemprop="cardinality" content="0..1">
<meta itemprop="group" content="auth-method">
</div>
<div itemprop="constraint" itemscope itemtype="https://schema.host/GroupConstraint">
<meta itemprop="group" content="auth-method">
<meta itemprop="cardinality" content="1..1">
</div>
</div>
An item with exactly one auth method passes:
PUT /users/alice.html HTTP/2
Content-Type: text/html
<!DOCTYPE html>
<html><body>
<div itemscope itemtype="https://example.com/UserAuth">
<meta itemprop="password" content="hashed-secret">
</div>
</body></html>
An item with both auth methods fails with 422:
PUT /users/bob.html HTTP/2
Content-Type: text/html
<!DOCTYPE html>
<html><body>
<div itemscope itemtype="https://example.com/UserAuth">
<meta itemprop="password" content="hashed-secret">
<meta itemprop="oauth-token" content="token123">
</div>
</body></html>
At least one contact method
<div itemprop="constraint" itemscope itemtype="https://schema.host/GroupConstraint">
<meta itemprop="group" content="contact-info">
<meta itemprop="cardinality" content="1..n">
</div>
With properties email, phone, and address all assigned to the contact-info group, at least one must be present.
Error cases
| Condition | Response |
|---|---|
Item under itemprop="constraint" missing group |
Silently skipped — not recognized as a group constraint |
Item under itemprop="constraint" with empty group |
Silently skipped — not recognized as a group constraint |
| Group cardinality violation | 422 with check: "group" and message containing the group name |
The itemtype on an item nested under itemprop="constraint" is not itself checked — whether an item is treated as a group constraint depends only on whether it carries a non-empty group value. Always use https://schema.host/GroupConstraint as shown above; an item of a different type that happens to carry a group field would still be enforced as one.
Group constraint validation runs only after cardinality, type, property-level @validate, and schema-level @validate have all passed.
The violation message follows the format: group '<name>' constraint violated: <cardinality error>.