Status
- Doc Status
-
Working Draft — Only experimental and ‘proof-of-concept’ apps should be built on this unstable draft.
- Proposed IANA Registrations
-
application/prs.hal-forms+json
- Repository
- Sample Implementation
- Last Updated
-
2021-03-03
1. Summary
This document describes a simple media type designed to add runtime FORM support for the [HAL] media type. This is an independent backward-compatible extension of the HAL media type and MUST NOT be treated as standard HAL or as part of the HAL specification [HALSPEC].
1.1. Motivation
The HAL media type is a popular format for representing API responses. One of the possible reasons for this popularity is that HAL does not include detailed information about state transitions like filtered requests (e.g. search, sort, etc.) or write operations (e.g. create, edit, delete, etc.) as part of the specification. This feature keeps the complexity of HAL responses relatively low and easy to deal with. However, this also means one of the challenges of using HAL for APIs that support dynamic user inputs and/or varying work flow patterns is client applications must encode the detailed transition information (args, methods, work flow) directly in the client code. That means clients must be updated each time the input or work flow details change.
The HAL-FORMS media type is an attempt to meet this challenge by creating a format and processing pattern to support dynamic UI forms for HAL responses. This is a backward-compatible, non-standard extension. There is nothing in this format or process pattern that adds breaking changes to the HAL media type itself. Clients that implement this extension can still be valid HAL clients by degrading gracefully (e.g. not throwing errors) when HAL-FORMS documents are not returned by the server.
Note
|
The HAL-FORMS media type design follows many of the HAL media type conventions. For this reason, HAL-FORMS "looks like HAL." However, it is important to keep in mind that HAL-FORMS is not the same as HAL — the two should not be thought of as interchangeable in any way. Finally, HAL-FORMS documents SHOULD always be sent over HTTP using the |
1.2. Updates
There is an open source repository [REPO] for this specification. Readers are encouraged to submit updates via the repository any time.
1.3. Compliance
An implementation (client or server) of this specification is not compliant if it fails to satisfy one or more of the MUST or REQUIRED elements. An implementation that satisfies all the MUST and REQUIRED elements as well as all the SHOULD and RECOMMENDED elements is said to be "unconditionally compliant"; one that satisfies all the MUST and REQUIRED elements but not all the SHOULD and RECOMMENDED elements is said to be "conditionally compliant."
Note
|
RFC2119 Words
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119]. |
2. The HAL-FORMS Media Type
The HAL-FORMS media type is a simple JSON [RFC7159] document that contains information on the HTTP method, message content-type, and parameters to use when making a templated request to a HAL server. This media type can be used to provide dynamic state transition descriptions at runtime.
2.1. Example HAL-FORMS document
Here is a simple HAL-FORMS document example:
{
"_links" : {
"self" : {
"href" : "http://api.example.org/rels/create"
}
},
"_templates" : {
"default" : {
"title" : "Create",
"method" : "POST",
"contentType" : "application/json",
"properties" : [
{"name" : "title", "required" : true, "value" : "", "prompt" : "Title", "regex" : "", "templated" : false},
{"name" : "completed", "required" : false, "value" : "false", "prompt" : "Completed", "regex" : ""}
]
}
}
}
2.2. The HAL-FORMS Media Type Identifier String
The media type identifier string for HAL-FORMS documents is: application/prs.hal-forms+json
This SHOULD be used as part of the HTTP accept
header when making a request for a HAL-FORMS document. It SHOULD appear as the HTTP content-type
header when sending a response that contains a HAL-FORMS document.
3. Properties of a HAL-FORMS Document
All HAL-FORMS documents MUST be valid JSON documents. A well-formed HAL-FORMS document has two top-level objects: _links
and _templates
. The following is a summary of the structure of the HAL-FORMS media type.
3.1. The _links
Collection
The _links
collection contains a dictionary collection of link
elements associated with the HAL-FORMS document.
3.1.1. _links
Contains the collection of valid link
elements in the HAL-FORMS document. This is a RECOMMENDED element. If this element is missing, is invalid, or cannot be parsed, the HAL-FORMS document SHOULD be treated as if it contains a _links
collection which contains a single link
element with the key of self
and the value of the URL that was used to request the current HAL-FORMS document.
Every HAL-FORMS document SHOULD have at least one link
element in the collection with a key
value set to self
. The _links
collection MAY have additional link
elements with other key
values. HAL-FORMS clients SHOULD ignore any link
elements with key
values they do not understand. Clients MAY reject a HAL-FORMS document that does not contain a link
element with the key
value set to self
.
3.1.2. link
The link
element consists of a key and a set of properties.
-
key
: The unique identifier of thelink
element. This is a REQUIRED property for eachlink
element. If this property is missing, is set to an unrecognized value, or cannot be parsed, the associatedlink
element SHOULD be ignored. -
href
: The URL associated with thekey
. This is a REQUIRED property. If this is missing, set to empty or cannot be parsed, the associatedlink
element SHOULD be ignored.
Note
|
Additional properties MAY appear within a link element. HAL-FORMS clients SHOULD ignore any properties they do not understand and/or cannot parse. |
3.2. The _templates
Collection
The _templates
collection describes the available state transition details including the HTTP method, message content-type, and arguments for the transition. This is a REQUIRED element. If the HAL-FORMS document does not contain this element or the contents are unrecognized or unparsable, the HAL-FORMS document SHOULD be ignored.
The _templates
element contains a dictionary collection of template
objects. A valid HAL-FORMS document has at least one entry in the _templates
dictionary collection. Each template
contains the following possible properties:
3.2.1. contentType
The value of contentType
is the media type the client SHOULD use when sending a request body to the server. This is an OPTIONAL element. The value of this property SHOULD be set to "application/json"
or "application/x-www-form-urlencoded"
. It MAY be set to other valid media-type values. If the contentType
property is missing, is set to empty, or contains an unrecognized value, the client SHOULD act is if the contentType
is set to "application/json"
. See Encoding Request Bodies for details.
3.2.2. key
The unique identifier for this template element. This is a REQUIRED element. For this release, the only pre-defined value for key
is "default"
. If there is only one element in the collection the key
value MUST be set to "default"
. Clients MAY ignore additional entries in the collection. If this element is missing, set to empty or is unparsable, this template object SHOULD be ignored.
3.2.3. method
The HTTP method the client SHOULD use when the service request. Any valid HTTP method is allowed. This is a REQUIRED element. If the value is empty or is not understood by the client, the value MUST be treated as an HTTP GET.
3.2.4. properties
An array of one or more anonymous property
elements (see The property
Element) that each describe a parameter for the associated state transition. This is an OPTIONAL element. If the array is missing or empty, the properties
collection MUST be treated as an empty set of parameters — meaning that the transition is meant to be executed without passing any parameters.
3.2.5. target
Contains the identifier of the target URL for the client to use when submitting the completed HAL-FORMS template. For example, if the client should submit the completed template to the following URL: http://api.example.org/jobs/
then the target
proprety would be target="http://api.example.org/jobs/"
.
This is an OPTIONAL property. If this property is not understood by the recipient, left blank, or contains an invalid URL string, it SHOULD be ignored.
The target
property holds the same information as the _htarget
query string property. If both the target
prorperty and the _htarget
query string value appear in the same message, the _htarget
query string SHOULD be used and the target
property SHOULD be ignored.
3.2.6. title
A human-readable string that can be used to identify this template. This is a valid JSON string. This is an OPTIONAL element. If it does not exist or is unparsable, consumers MAY use the key
value of the template as the value for title
.
3.3. The property
Element
A JSON object that describes the details of the state transition element (name
, required
, readOnly
, etc.). It appears as an anonymous array of properties
as a child of the _templates
element (See The _templates
Element).
There is a set of property
attributes that are considered core attributes. There are is also group of property
attributes that are considered additional attributes. Any library supporting the HAL-FORMS specification SHOULD support all of the core attributes and MAY support some or all of the additional attributes.
3.3.1. Core property
Attributes
The core property
attributes cover the basics of describing a single value used for a state transition (write or filter parameter). Most all attributes are OPTIONAL and MAY be ignored by HAL-FORMS processors. Below is a list of all the core property
attributes.
Note
|
Any library, tooling, or utility supporting the HAL-FORMS specification SHOULD support all of the core |
3.3.1.1. name
The property
name. This is a valid JSON string. This is a REQUIRED element. If this attribute is missing or set to empty, the client SHOULD ignore this property
object completely.
3.3.1.2. prompt
The human-readable prompt for the parameter. This is a valid JSON string. This is an OPTIONAL element. If this element is missing, clients MAY act as if the prompt
value is set to the value in the name
attribute.
3.3.1.3. readOnly
Indicates whether the parameter is read-only. This is a valid JSON boolean. This is an OPTIONAL element. If this element is missing, empty, or set to an unrecognized value, it SHOULD be treated as if the value of readOnly
is set to ‘false’.
3.3.1.4. regex
A regular expression string to be applied to the value of the parameter. Rules for valid values are the same as the HTML5 pattern attribute [HTML5PAT]. This is an OPTIONAL element. If this attribute missing, is set to empty, or is unparseable , it SHOULD be ignored.
3.3.1.5. required
Indicates whether the parameter is required. This is a valid JSON boolean. This is an OPTIONAL element. If this attribute is missing, set to blank or contains an unrecognized value, it SHOULD be treated as if the value of required
is set to ‘false’.
3.3.1.6. templated
Indicates whether the value
element contains a URI Template [RFC6570] string for the client to resolve. This is a valid JSON boolean. This is an OPTIONAL element. If this element is missing, set to empty, or contains unrecognized content, it SHOULD be treated as if the value of
templated
is set to ‘false’.
3.3.1.7. value
The property
value. This is a valid JSON string. This string MAY contain a URI Template (see templated
for details). This is an OPTIONAL element. If it does not exist, clients SHOULD act as if the value
property is set to an empty string.
3.3.2. Additional property
Attributes
The additional property
attributes provide greater controls for describing the rendering and validation of input controls for a state transition (write and filter parameters). All of the additional attributes are OPTIONAL and one or more of them MAY be ignored by HAL-FORMS processors. Below is a list of all the additional property
attributes.
Note
|
Any library, tooling, or utility supporting the HAL-FORMS specification MAY support some or all of the additional |
3.3.2.1. cols
The cols
attribute specifies the expected maximum number of characters per line to display when rendering the input box. This attribute applies to the associated property
element when that property
element’s type
attribute is set to textarea
. The cols
attribute is a non-negative integer greater than zero. If the cols
attribute is missing or contains an invalid value, it can be assumed to be set to the value of 40
. If the type
attribute of the associated property
element is not set to textarea
, this attribute SHOULD be ignored. This is an OPTIONAL attribute and it MAY be ignored. The cols
attribute SHOULD appear along with the rows
attribute.
3.3.2.2. max
The max
attribute specifies the maximum numeric value for the value
setting of a property
element. This attribute MAY appear along with the min
attribute. This is an OPTIONAL property and it MAY be ignored.
3.3.2.3. maxLength
The maxLength
attribute specifies the maximum number of characters allowed in the value
property. This attribute MAY appear along with the minLength
attribute. This is an OPTIONAL property and it MAY be ignored.
3.3.2.4. min
The min
attribute specifies the minimum numeric value for an value
setting of a property
element. This attribute MAY appear along with the max
attribute. This is an OPTIONAL property and it MAY be ignored.
3.3.2.5. minLength
The minlength
attribute specifies the minimum number of characters required in a value
property. this attribute MAY appear along with the maxLength
attribute. This is an OPTIONAL property and it MAY be ignored.
3.3.2.6. options
The options
element contains a set of possible values accessible either byValue (e.g. inline
) or byReference (e.g. via link.href
) and can be used to provide a constrained list of possble values for a property
field. See The options
Element for details.
Support for the options
object of a property
element is OPTIONAL. If the client does not understand or cannot parse the options
element, the options
element SHOULD be ignored and the corresponding property
SHOULD be treated as a simple text input element.
3.3.2.7. placeholder
The placeholder
attribute specifies a short hint that describes the expected value of an input field (e.g. a sample value or a short description of the expected format). This is an OPTIONAL field and MAY be ignored.
3.3.2.8. rows
The rows
attribute specifies the expected maximum number of lines to display when rendering the input box. This attribute applies to the associated property
element when that property
element’s type
attribute is set to "textarea"
. The cols
attribute is a non-negative integer greater than zero. If the cols
attribute is missing or contains an invalid value, it can be assumed to be set to the value of 5
. If the type
attribute of the associated property
element is not set to "textarea"
, this attribute SHOULD be ignored. This is an OPTIONAL attribute and it MAY be ignored. The rows
attribute SHOULD appear along with the cols
attribute.
3.3.2.9. step
The step
attribute specifies the interval between legal numbers in a value
property. For example, if step="3"
, legal numbers could be -3, 0, 3, 6, etc.
3.3.2.10. type
The type
attribute controls the data type of the property
value. It is an enumerated attribute. The type
can also used to determine the interface control to display for user input. This is an OPTIONAL element. If the type
value is not supported by the document consumer, contains a value not understood by the consumer, and/or is missing, the the document consumer SHOULD assume the type
attribute is set to the default value: "text"
and render the display input as a simple text box.
Possible settings for the type
value adn teh expected contents to be returned inthe are:
hidden
,
text
,
textarea
,
search
,
tel
,
url
,
email
,
password
,
date
,
month
,
week
,
time
,
datetime-local
,
number
,
range
,
color
.
For hints on how to render and process various type
values as well as for guidance on how each type
value affects to the contents of the associated value
property, see [HTML5TYPE].
3.4. The options
Element
The options
element contains an enumerated list of possible values for a property
. This can be used to provide a UI similar to HTML controls such as:
-
SELECT & OPTIONS
-
INPUT.type="radio"
-
INPUT.type="checkbox"
-
INPUT.type="search"
(w/ type-ahead suggestions)
The options
control can also be used in machine-to-machine interactions where it is important to provide the client information about the possible values for a property
.
The options
element contains a set of possible values accessible either by value (e.g. options.inline
) or by reference (e.g. via options.link.href
) and can be used to provide a constrained list of possble values for a property
field. If, when first loaded, the HAL-FORMS template has a pre-set value in the corresponding property.options.selectedValues
array attribute, the UI MAY render the form with selected value(s) already chosen.
Whatever value is ultimately selected gets placed into the property.options.selectedValues
array attribute. When sending the results of the completed HAL-FORMS to the server, content property.options.selectedValues
is serialized in a manner compliant with the media type value in the contentType
attribute (e.g. appilcation/json
, application/x-www-form-urlencded
, etc.).
Note
|
Support for the options element of a property element is OPTIONAL. If the client does not understand or cannot parse the options element, the options element SHOULD be ignored and the corresponding property SHOULD be treated as a simple text input element. |
3.4.1. Overview of the options
Element
Below is an overview of the property.options
element as it appears within a HAL-FORMS document. Details describing the meaning and use of all the elements of the design appears in the sections that follow.
{
"_templates" : {
"default" : {
...
"contentType" : "application/json|application/x-www-form-ulencoded",
"properties" : [
{
"name" : "...",
"prompt" : "...",
"options" : {
"selectedValues" : ["...", "...", ...],
"inline" : ["...", "..." , ...] | [{"prompt" : "...", "value" : "..."}, {...}, ...],
"link" : {
"href" : "...",
"templated" : "true|false",
"type" : "application/json|text/csv..."
},
"promptField" : "...",
"valueField" : "...",
"minItems" : 0,
"maxItems" : 1
}
}
]
}
}
}
Not all the elements of the options
object shown above are valid at the same time.
3.4.2. options
Attributes
Below is the list of options
attribute. HAL-FORMS compliant applications that support the options
element SHOULD support all the attributes listed here.
3.4.2.1. inline
The inline
attribute is a JSON array that contains the list of possible values. The inline
attribute is OPTIONAL. If the inline
attribute is missing or unparseable and the link
(see link
) attribute is missing or unparseable, then the options
element SHOULD be ignored.
In it’s simplest form, the inline
attribute holds a set of anonymous JSON dictionary objects in the form {'"prompt": "...", "value" : ""}
(see A Simple Inline Array of Values). The inline
contents can also be an array of unique name-value pairs (see An Inline Array of Name/Value Pairs).
Note
|
If both inline and link elements appear in the same options object, the inline element SHOULD be used and the link element SHOULD NOT be used. |
3.4.2.2. link
The link
attribute is a JSON dictionary object that contains an href
which points to an external HTTP resource which contains the collection of possible values for a property'. The +link
attribute is OPTIONAL. If the link
attribute is missing or unparseable and the inline
(see inline
) attribute is missing or unparseable, then the options
element SHOULD be ignored.
The link
attribute has the following child attributes:
-
href
: The URL associated with the key. This is a REQUIRED property. If this is missing, set to empty or cannot be parsed, the associated link element SHOULD be ignored. -
type
: A string used as a hint to indicate the media type expected when dereferencing the target resource. This is an OPTIONAL attribute. Thetype
value SHOULD be set toapplication/json
ortext/csv
. It MAY be set to some other value. If thetype
attribute is missing or unparseable, it SHOULD be assumed to be set toapplication/json
. Client applications SHOULD use the value of thetype
attribute to populate the HTTPAccept
header. -
templated
: A boolean value that SHOULD be set totrue
whenlink.href
contains a URI Template [RFC6570]. This is an OPTIONAL attribute. If it is missing or unparseable, the value oftemplated
SHOULD be treated as set tofalse
.
The value returned when dereferencing a link
element SHOULD be either a simple array (see An External Array of Values) or a custom collection (see An External Array of Name/Value Pairs). The exact format of the returned collection will vary based on the value of the HTTP Accept
header sent with the request.
When responding to an options.link
request, the server MAY return additional fields (e.g. more than prompt
and value
fields). These additional fields SHOULD be ignored by the client application.
Note
|
If both inline and link elements appear in the same options object, the inline element SHOULD be used and the link element SHOULD NOT be used. |
3.4.2.3. maxItems
Indicates the maximum number of items to return in the selectedValues
attribute. The client application MAY use this as a UI hint and/or to perform a client-side validation. The maxItems
attribute is OPTIONAL. When it is missing or unparseable, the application SHOULD treat the maxItems
value as unbounded (e.g. there is no upper limit on the number of items that can be selected and returned).
3.4.2.4. minItems
Indicated the minimum number of items to return in the selectedValues
attribute. The client application MAY use this as a UI hint and/or to perform a client-side validation. The minItems
attribute is OPTIONAL. When it is missing or unparseable, the application SHOULD treat the minItems
value as 0
(e.g. there is no minimum number of items to be selected and returned).
Note
|
Document authors need to take care that property.required and property.options.minItems settings do not conflict (e.g. property.required:true and options.minItems:0 ). |
3.4.2.5. promptField
This attribute contains the name of the JSON dictionary element in the array returned via the inline
or link
elements to use as the prompt when rendering the options
UI. This is an OPTIONAL attribute. If this attribute is missing or unparseable the application SHOULD assume the promptField
value is set to "prompt"
.
See Reference Fields for an example.
3.4.2.6. selectedValues
This is a JSON array that holds the set of values selected from the list of possible values supplied by the inline
and link
attributes. This is an OPTIONAL element. If it is missing or unparseable, the application SHOULD assume it is an empty JSON array.
This attribute MAY be populated when the HAL-FORMS is first requested. In that case, the application can use the value of the selectedValues
array to pre-populate the user interface.
When sending the results of selecting multiple values in the options.selectedValues
array from the client to the server, the rules associated with the _templates.contentType
SHOULD be applied. When the _templates.contentType
is set to application/json
, the contents of the options.selectedValues
array SHOULD be serialized as a simple JSON array:
{
...
shipping=["FedEx", "DHL"]
...
}
When the contentType
is set to application/x-www-form-urlencoded
, the contents of the options.selectedValues
array SHOULD be serialized as a set of repeating name/value pairs:
shipping=FedEx&shipping=DHL
See Multiple Return Values for an example.
3.4.2.7. valueField
This attribute contains the name of the JSON dictionary element in the array returned via the inline
or link
elements to use as the value when rendering the options
UI and filling in the selectedValues
attribute. This is an OPTIONAL attribute. If this attribute is missing or unparseable the application SHOULD assume the valueField
value is set to "value"
.
See Reference Fields for an example.
3.4.3. Additional Considerations
Here are some additional considerations when implementing support for the property.options
element.
3.4.3.1. Missing Prompts
In cases where the possible value collection from (inline
or link
elements) only supplies a list of value
elements, the client SHOULD operate as if a prompt
element was supplied and set that prompt
value to equal the contents of the corresponding value
element.
3.4.3.2. Supporting JSON and CSV
Compliant applications SHOULD support both application/json
and text/csv
as valid response types for options.link
implementations. Clients MAY support other values. If no options.link.type
attribute exists, the client application SHOULD default to application/json
. Whether the options.link.type
value appears or not, client applications SHOULD send an Accept
header when making a request to the server with the supplied URL. If no Accept
header is sent by the client, the server SHOULD assume the client expects an Accept
header set to application/json
and respond accordingly.
3.4.4. options
Examples
Not all the elements of the options
object shown above are valid at the same time. There are a number of possible "renditions" of the options
object. This spec covers the following:
-
A Simple Inline Array of Values
-
An Inline Array of Name/Value Pairs
-
An External Array of Values
-
An External Array of Name/Value Pairs
-
Reference Fields
-
Multiple Return Values
3.4.4.1. A Simple Inline Array of Values
Below is a simple rendition of the options
control using the Inline Array style. Note that, in the example below control’s default value would be set to "FedEx".
{
"_templates" : {
"default" : {
...
"properties" : [
{
"name" : "shipping",
"prompt" : "Select Shipping Method",
"options" : {
"selectedValues" : ["FedEx"],
"inline" : ["FedEx","UPS","DHL"]
}
}
]
}
}
}
A corresponding HTML.SELECT
rendering looks like this:
<label for="shipping">Select Shipping Method</label>
<select name="shipping">
<option selected="true">FedEx</option>
<option>UPS</option>
<option>DHL</option>
</select>
3.4.4.2. An Inline Array of Name/Value Pairs
Below is an example of the options
control using an Inline Array of Name/Value Paris.
{
"_templates" : {
"default" : {
...
"properties" : [
{
"name" : "shipping",
"type" : "radio",
"prompt" : "Select Shipping Method",
"options" : {
"selectedValues" : ["FedEx"],
"inline" : [
{"prompt" : "Federal Express", "value" : "FedEx"},
{"prompt" : "United Parcel Service", "value" : "UPS"},
{"prompt" : "DHL Express", "value" : "DHL"}
]
}
}
]
}
}
}
A corresponding HTML.INPUT.type="radio"
rendering looks like this:
<p>
<input type="radio" id="fedex" name="shipping" value="FedEx" checked="true">
<label for="fedex">Federal Express</label><br>
<input type="radio" id="ups" name="shipping" value="UPS">
<label for="ups">United Parcel Service</label><br>
<input type="radio" id="dhl" name="shipping" value="DHL">
<label for="dhl">DHL Express</label>
</p>
3.4.4.3. An External Array of Values
The source of possible values for a options
control can also be an external resource. This resource is reachable using an HTML.GET
against a supplied URL (which MAY be templated) and and OPTIONAL options.link.type
property that holds a valid registered media type (e.g. application/json
, text/csv
, etc.).
By default, the response value is a Simple Array rendered in application/json
as a JSON array.
{
"_templates" : {
"default" : {
...
"properties" : [
{
"name" : "shipping",
"type" : "radio",
"prompt" : "Select Shipping Method",
"options" : {
"selectedValues" : ["FedEx"],
"link" : {
"href" : "http://api.examples.org/shipping-options",
"templated" : "false",
"type" : "application/json"
}
}
}
]
}
}
}
The client SHOULD dereference the URL using HTTP.GET
. The exchange (including the response) looks like this:
*** REQUEST
GET /shipping-options HTTP/2.0
Host: api.example.org
Accept: application/json
*** RESPONSE
HTTP/2.0 200 OK
Content-Type: application/json
Content-Length: nn
["Fedex","UPS","DHL"]
A CR-LF delimited set of values MAY be returned if the options.link.type
attribute is set to text/csv
*** REQUEST
GET /shipping-options HTTP/2.0
Host: api.example.org
Accept: text/csv
*** RESPONSE
HTTP/2.0 200 OK
Content-Type: text/csv
Content-Length: nn
Fedex
UPS
DHL
3.4.4.4. An External Array of Name/Value Pairs
The external resource MAY return a collection of name/value pairs.
{
"_templates" : {
"default" : {
...
"properties" : [
{
"name" : "shipping",
"type" : "dropdown",
"prompt" : "Select Shipping Method",
"options" : {
"selectedValues" : ["FedEx"],
"link" : {
"href" : "http://api.examples.org/shipping-options",
"templated" : "false",
"type : "application/json"
}
}
}
]
}
}
}
The client SHOULD dereference the URL using HTTP.GET
. The exchange (including the response) looks like this:
*** REQUEST
GET /shipping-options HTTP/2.0
Host: api.example.org
Accept: application/json
*** RESPONSE
HTTP/2.0 200 OK
Content-Type: application/json
Content-Length: nn
[
{"prompt" : "Federal Express", "value" : "FedEx"},
{"prompt" : "United Parcel Service", "value" : "UPS"},
{"prompt" : "DHL Express", "value" : "DHL"}
]
The set of name/value pairs MAY be returned in text/csv
format when the options.link.type
property is set to text/csv
.
*** REQUEST
GET /shipping-options HTTP/2.0
Host: api.example.org
Accept: text/csv
*** RESPONSE
HTTP/2.0 200 OK
Content-Type: text/csv
Content-Length: nn
Federal Express,FedEx
United Parcel Service,UPS
DHL Express,DHL
3.4.4.5. Reference Fields
The options
element also supports the use of options.promptField
and options.valueField
as custom property names or Reference Fields instead of using the default names "prompt"
and "value"
. In this case, the promptField
value contains the name of the field in the source collection (inline
or link
) to be used for prompts and the valueField
value contains the name of the field in the source collection to be used for values.
{
"_templates" : {
"default" : {
...
"properties" : [
{
"name" : "shipping",
"type" : "radio",
"prompt" : "Select Shipping Method",
"options" : {
"selectedValues" : ["FedEx"],
"inline" : [
{"shipName" : "Federal Express", "shipCode" : "FedEx"},
{"shipName" : "United Parcel Service", "shipCode" : "UPS"},
{"shipName" : "DHL Express", "shipCode" : "DHL"}
],
"promptField" : "shipName",
"valueField" : "shipCode"
}
}
]
}
}
}
Reference Fields MAY be used when returning an array of JSON objects if the options.accept
attribute is set to application/json
*** REQUEST
GET /shipping-options HTTP/2.0
Host: api.example.org
Accept: application/json
*** RESPONSE
HTTP/2.0 200 OK
Content-Type: application/json
Content-Length: nn
[
{"shipName" : "Federal Express", "shipCode" : "FedEx"},
{"shipName" : "United Parcel Service", "shipCode" : "UPS"},
{"shipName" : "DHL Express", "shipCode" : "DHL"}
]
3.4.4.6. Multiple Return Values
You can signal the minimum and maximum number of items that can be selected using the options.minItems
and options.maxItems
attributes. By default, these attributes are options.minItems=0
and options.maxItems
is unbounded (e.g. there are no limits). Client applications SHOULD validate the number of seleted values using these attributes. This can apply whether the source list comes from inline
or link
. These attributes are OPTIONAL and MAY be ignored by the client.
{
"_templates" : {
"default" : {
...
"properties" : [
{
"name" : "shipping",
"type" : "checkbox",
"prompt" : "Select Shipping Method",
"options" : {
"selectedValues" : ["FedEx"],
"inline" : [
{"shipName" : "Federal Express", "shipCode" : "FedEx"},
{"shipName" : "United Parcel Service", "shipCode" : "UPS"},
{"shipName" : "DHL Express", "shipCode" : "DHL"}
],
"minItems" : 1,
"maxItems" : 2
"promptField" : "shipName",
"valueField" : "shipCode"
}
}
]
}
}
}
When sending the results of selecting multiple values in the options.selectedValues
array from the client to the server, the rules associated with the contentType
SHOULD be applied. When the contentType
is set to application/json
, the contents of the options.selectedValues
array SHOULD be serialized as a simple JSON array:
{
...
shipping=["FedEx", "DHL"]
...
}
When the contentType
is set to application/x-www-form-urlencoded
, the contents of the options.selectedValues
array SHOULD be serialized as a set of repeating name/value pairs:
shipping=FedEx&shipping=DHL
4. The HAL-FORMS Query String Registry
The HAL-FORMS media type supports a set of OPTIONAL query string parameters. These can be passed when requesting HAL-FORMS documents in order to provide additional information (e.g. document identifiers, etc.) to the server when a client requests a HAL-FORMS document. For example, the server can use these parameter values to validate the HAL-FORMS request and/or use them to determine how to pre-populate the HAL-FORMS document before returning it to the client.
Below is the list of query string values defined for this release of the specification. One or more of these parameters MAY appear in the URLs used to request HAL-FORMS documents. They can appear in the query string in any order. One or more (possibly all) these parameters MAY be ignored by servers receiving the HAL-FORMS request.
4.1. _hdoc
Contains the identifier (usually a URL) of the HAL document from which this request was derived. For example if the HAL document had a URL of http://api.example.org/users/123
then the _hdoc
query parameter would be _hdoc=http%3A%2F%2Fapi.example.org%2Fusers%2F123
.
4.2. _hkey
Contains the key
value of the HAL-FORMS template the client wishes to receive. For example, if the HAL-FORMS template key
is default
then the _hkey
parameter would be _hkey=default
.
4.3. _hmethod
Contains the HTTP method to be used when populating the HAL-FORMS method
value in the _template
. For example, if the client wishes to execute an HTTP POST with the template, the _hmethod
parameter would be: _hmethod=post
.
4.4. _hrel
Contains the key
of the HAL _link
element that identified the URL for the HAL-FORMS document. For example, if the HAL document had a _link
element that looked like this:
"http://api.example.org/rels/filter": {
"href": "http://api.example.org/task-list/",
"title": "Filter Tasks",
"templated": false
}
…then the _hrel
parameter would be _hkey=http%3A%2F%2Fapi.example.org%2Frels%2Ffilter
.
4.5. _hsource
Contains the identifier of the source record to use when pre-populating the HAL-FORMS document. For example, if the client wishes to edit the resource identified by the URL http://api.example.org/users/123
then the _hsource
parameter would be _hsource=http%3A%2F%2Fapi.example.org%2Fusers%2F123
.
4.6. _htarget
Contains the identifier of the target URL for the client to use when submitting the completed HAL-FORMS template. For example, if the client should submit the completed template to the following URL: http://api.example.org/jobs/
then the _htarget
parameter would be _htarget=http%3A%2F%2Fapi.example.org%2Fjobs%2F
.
Note
|
Additional HAL-FORMS query string parameters MAY be added over time. Implementers are also allowed to create their own HAL-FORMS query string parameters for local use as long as they do not overwrite or redefine existing query string parameters. Implementers are encouraged to use their own unique prefix value to reduce the chance their custom query parameters will conflict with other existing or future parameter names. |
5. Encoding Requests
Once the client application has used the HAL-FORMS document to render a UI for accepting inputs (and the user has supplied the inputs), that same document SHOULD be used to encode a request to send to the server to execute the state transition described by the HAL-FORMS document. There are two ways in which HAL-FORMS documents can be used to construct parameterized requests. The first is by encoding request URLs for HTTP GET, DELETE, and HEAD requests. The second is by encoding request bodies for HTTP PUT, POST, and PATCH requests.
5.1. Encoding Request URLs
When clients are instructed to send a request without a body (e.g. GET, HEAD, DELETE), clients SHOULD use the list of property
object’s name
and value
attributes to construct a valid URL using the W3C Mutate Action URL Algorithm [HTML5MUT] to produce a valid query string. Below is a simple HAL-FORMS document that uses the GET method and the resulting updated URL.
// HAL RESPONSE
{
"_links": {
"self": {
"href": "http://api.example.org/task-list/",
"title": "Reload",
"templated": false
},
"http://api.example.org/rels/filter": {
"href": "http://api.example.org/task-list/",
"title": "Filter Tasks",
"templated": false
},
}
}
// HAL FORMS DOCUMENT
{
"_links" : {
"self" : {
"href" : "http://api.example.org/rels/filter"
}
},
"_templates" : {
"default" : {
"title" : "Filter",
"method":"GET",
"properties": [
{"name":"title", "value":"", "prompt":"Title"},
{"name":"completed", "value":"", "prompt":"Completed", "regex":"^(true|false)$"}
]
}
}
}
// RESULTING URL
http://api.example.org/task-list/?title=sample&completed=false
Note
|
The HAL media type already defines support for parameterized HTTP GET queries using URITemplates. However, the HAL-FORMS document can be treated as an alternate implementation for GET queries that include additional constraints such as prompts, regular expression validators, etc. |
5.2. Encoding Request Bodies
When clients are instructed to send a request with a body (e.g. PUT, POST, PATCH), there are several possible content-types to use. Compliant applications MUST support encoding bodies using application/json
and SHOULD support encoding bodies using application/x_www-form-urlencoded
. Clients MAY support other content-types not listed in this document.
5.2.1. Sending application/json
Bodies
When sending bodies encoded as application/json
, clients SHOULD construct a simple JSON dictionary object that contains a set of name-value pairs that match the property
objects in the HAL-FORMS document. For example, using the Example HAL-FORMS document (see above) as a guide, a client would construct a JSON dictionary object that looks like the following:
{
"title" : "A Sample HAL Forms Response",
"completed" : false
}
5.2.2. Sending application/x-www-form-urlencoded
Bodies
When sending bodies encoded as application/x-www-form-urlencoded
, clients SHOULD construct a body that is in compliance with the guidance in the W3C FORMS Encoding Algorithm [HTML5ENC]. A sample (using the Example HAL-FORMS document) follows:
title=A+Sample+HAL+Forms+Response&completed=false
5.2.3. Sending Bodies for Other Media Types
Providers who supply responses that contain contentType
values not covered in this specification SHOULD publish documentation instructing clients on the proper way to construct request bodies from HAL-FORMS documents.
6. Suggested Process Flow for HAL-FORMS Documents
While it is completely up to providers and consumers to determine how they wish to use the HAL-FORMS media type, the following is a suggested process flow for runtime use of HAL-FORMS documents on the Web.
-
Servers emit HAL responses that contain
rel
values which are valid URLs that return HAL-FORMS documents. -
Clients parse the HAL response and (either on-demand or in pre-fetch mode) request the HAL-FORMS documents.
-
When a HAL-FORMS document is returned by the server, clients use this information to render an input UI for humans when needed.
-
Clients collect the completed user inputs and, based on the value of
contentType
, craft a valid request to send to the server and execute that request.
What follows is an illustrated example of this process flow.
6.1. Starting With a Typical HAL Response.
A client application can start with a typical HAL response and use information in the representation to see if HAL-FORMS documents are available. Below is a HAL response w/ URLs for rel
values. These MAY point to HAL-FORMS documents.
**** REQUEST
GET /task-list/ HTTP/1.1
Host: api.example.org
Accept: application/vnd.hal+json
**** RESPONSE
HTTP/1.1 200 OK
Content-Type: application/vnd.hal+json
Date: Wed, 01 Jun 2016 14:50:30 GMT
{
"_links": {
"self": {
"href": "http://api.example.org/task-list/",
"title": "Reload",
"templated": false
},
"http://api.example.org/rels/create": {
"href": "http://api.example.org/task-list/",
"title": "Add Task",
"templated": false
},
"http://api.example.org/rels/tasks": [
{
"href": "http://localhost:8181/1a14qx7qc81",
"title": "Yard Work"
},
{
"href": "http://localhost:8181/1d4jwe1ewt7",
"title": "Home Work"
},
{
"href": "http://localhost:8181/1e2ll5wa383",
"title": "School Work"
}
]
}
}
6.2. Requesting a HAL-FORMS Document
After parsing the HAL response, a HAL-FORMS compliant client app MAY use the rel
URLs to make requests for HAL-FORMS documents. In the case of this example, the http://api.example.org/rels/create
is used to see if there is a HAL-FORMS document available.
**** REQUEST
GET /rels/create HTTP/1.1
Host: api.example.org
Accept: application/prs.hal-forms+json
**** RESPONSE
HTTP/1.1 200 OK
Content-Type: application/prs.hal-forms+json
Date: Wed, 01 Jun 2016 14:59:30 GMT
{
"_links" : {
"self" : {
"href" : "http://api.example.org/rels/create"
}
},
"_templates" : {
"default" : {
"title" : "Create",
"method" : "POST",
"contentType" : "application/json",
"properties" : [
{"name" : "title", "required" : true, "value" : "", "prompt" : "Title", "regex" : "", "templated" : false},
{"name" : "completed", "required" : false, "value" : "false", "prompt" : "Completed", "regex" : ""}
]
}
}
}
6.3. Sending a HAL-FORMS Body Request
After receiving the HAL-FORMS response and rendering the UI, the client application can — once the user supplies inputs and executes the "submit" action — use the instructions in the HAL-FORMS document to compose a request and send it to the URL indicated in the HAL document response (as follows):
**** REQUEST
POST /task-list/ HTTP/1.1
Host: api.example.org
Accept: application/json
{
"title" : "A Sample HAL-FORMS Response",
"completed" : false
}
**** RESPONSE
HTTP/1.1 201 OK
Content-Type: application/vnd.hal+json
Date: Wed, 01 Jun 2016 15:03:30 GMT
...
7. Extending the HAL-FORMS Document
Authors can extend the HAL-FORMS media type as long as the following rules are observed:
-
No existing properties or objects are removed.
-
No existing properties or objects or the list of valid values are altered in a way that is non-backward compatible (e.g. changes MUST NOT break existing implementations that adhere to this specification).
-
All new properties or objects are treated as OPTIONAL (e.g. no new REQUIRED elements are introduced in an extension).
Warning
|
Authors should be aware that a future version of this specification MAY add new elements and should take care that any extensions are implemented in a way that reduces the likelihood that a future version of this specification is in conflict with your extension. |
8. References
-
[HAL] Kelly, M. "HAL - Hypertext Application Language", September 2013, http://stateless.co/hal_specification.html
-
[HALSPEC] Kelly, M. "JSON Hypertext Application Language" (Draft), July 2015 https://tools.ietf.org/html/draft-kelly-json-hal-07
-
[REPO] Github, "HAL-FORMS", https://github.com/RWCBook/hal-forms
-
[RFC2119] Bradner, S.,"Key words for use in RFCs to Indicate Requirement Levels", March 1997, http://tools.ietf.org/html/rfc2119
-
[RFC7159] Bray, T. "The JavaScript Object Notation (JSON) Data Interchange Format", March 2014, https://tools.ietf.org/html/rfc7159
-
[HTML401] Raggett, D., Ed. et al", "HTML 4.01 Specification", December 1999, https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
-
[HTML5PAT] Hickson, I., Ed. et al, "HTML5 (The Pattern Attribute)", October 2014, http://www.w3.org/TR/html5/forms.html#the-pattern-attribute
-
[RFC6570] Gregorio, J., et al, "URI Template", March 2012, https://tools.ietf.org/html/rfc6570
-
[HTML5MUT] Hickson, I., Ed. et al, "HTML5 (Mutate Action URL)", October 2014, http://www.w3.org/TR/html5/forms.html#submit-mutate-action
-
[HTML5ENC] Hickson, I., Ed. et al, "HTML5 (Encoding Algorithm)", October 2014, http://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
-
[HTML5TYPE] "HTML 5.2 FORMS", December 2017, https://www.w3.org/TR/html52/sec-forms.html#element-attrdef-input-type
-
[RFC8259] Bray, Tim, Ed., "Javascript Object Notation", December 2017, https://tools.ietf.org/html/rfc8259
-
[RFC4180] Y. Shafranovich, "Common Format and MIME Type for Comma-Separated Values (CSV) Files", October 2005, https://tools.ietf.org/html/rfc4180
9. Acknowledgements
Thanks to everyone who helped contribute to this specification including: Carlos Beltrame, Josh Cohen, Oliver Drotbohm, Pete Johanson, Mike Kelly, Dilip Krishnan, Evert Pot, Greg Turnquist.