Page History
Table of Contents |
---|
Background
We've already discussed how to to add hypermedia to a resource using using the standard HAL HAL _links and and _embedded reserved reserved properties. These properties These properties will cover the majority of your hypermedia needs. However, in this same article we introduced the the AddFormAction service service to address hypermedia address hypermedia requirements that go beyond the design intent of the the _links and and _embedded properties properties.
To understand the the AddFormAction service service, it is important to understand the inspiration behind its design: HTML. As most developers will recognizewill recognize, HTML is both a a media type and a and a markup language. Because it is a media type, we can borrow from its well defined and understood understood hypermedia controls when when defining similar capabilities for the JSON media type. In HTML, we find that that hypermedia controls are are used for three general three general purposes:
- To To identify related resources through through hyperlinks that allow the client to change the application state (e.g., the the <a> tag).
- To To embed resources from from another URI into the current resource (e.g., the the <img> tag).
- To provide the client client input and submit capabilities to to interact with the current resource (e.g., the the <form> tag.)
It would seem that HAL covers the first two purposes reasonably well. The The _links property property provides the same purpose as the the <a>
tag tag and the the _em bedded property embedded property provides the same purpose as tags like like <img>
(which is just one of a few tags that embed resources). However, the third purpose third purpose - the ability to provide richer interaction with the resource via form-like controls - is not addressed by HAL.
New Reserved Property: _forms
In keeping with the spirit of HTML hypermedia controls, the SRP HTTP Framework supports a custom property called called _forms. It serves the same purpose same purpose as the HTML HTML <form>
tag tag and borrows some of the same element names. Here is an example of what what _forms hypermedia hypermedia controls looks likelooks like:
Code Block | ||
---|---|---|
| ||
{ "_forms":{ "addPhone":{ "method":"POST", "action":"https://www.examples.org/api/user/matthew/phone", "title":"Add Phone", "fields":{ "type":{ "default":"Cell", "required":true, "visible":true }, "number":{ "default":"", "required":true, "visible":true } } } } } |
The The _forms property property contains one or more more sub-properties. Each Each sub-property name name defines a unique unique form action and and is typically named in a verba verb+noun format (e.g., addPhone in in the above example). The The sub-property values values are themselves additional sub-property name/value pairs.
Each defined defined form action contains contains the following following sub-properties:
- method to to indicate the HTTP method used when making the request to the server. (Required)
- action to to indicate the target URI for the request. (Required)
- title to to provide a user-friendly label for the the form action. (Optional)
- fields to to identify relevant properties from the primary resource object and object and to document how they are to be handled. (Optional)
In the above example, the intent of this this form action is is to describe how a new phone number can be added to the current resource. Clients should be should be able to consume this meta data and discover that this is done by sending a JSON object containing the the type and and number properties properties via a POST to the indicated URI.
fields Sub-Property
The The fields sub sub-property contains one or more more sub-properties. Each of these these sub-properties are the are the names of a a property in in the primary resource objectresource object. In the above example, type and and number are are expected to be properties within the primary resource object. The The sub-property values are themselves values are themselves additional sub-property name/value pairs.
Each defined defined field name contains contains one or more of the following following sub-properties:
- default to to indicate the value of the resource object property that should be submitted unless overridden by the client.
- required to to indicate that this resource object property must have a value in order for the the form action to to be accepted.
- visible to to indicate if this resource object property should be visible to the client.
Hierarchical Outline
To help visualize the _forms structure, here is a general outline:
Infopanel | ||
---|---|---|
| ||
|
Using the AddFormAction Service AddFormAction Service
With our background out of the way, we can now demonstrate how to call the the AddFormAction service service. To make this easy, we'll implement the the form action that that appears in the above example:
Code Block | ||
---|---|---|
| ||
API customers.ID.GET KeyID = EndpointSegment ColumnNames = 'FIRST_NAME' : @FM : 'LAST_NAME' : @FM : 'ADDRESS' : @FM : 'CITY' : @FM : 'STATE' : @FM : 'ZIP' PropertyNames = 'firstName' : @FM : 'lastName' : @FM : 'address' : @FM : 'city' : @FM : 'state' : @FM : 'zipCode' // Create a JSON object in memory. objResource = HTTP_Resource_Services('GetObject', 'CUSTOMERS', KeyID, ColumnNames, PropertyNames) If Error_Services('NoError') then // Add _forms sub-property hypermedia control. Fields = 'type' : @FM : 'number' FieldProperties = 'Cell' : @VM : True$ : @VM : True$ : @FM : '' : @VM : True$ : @VM : True$ HTTP_Resource_Services('AddFormAction', objResource, 'addPhone', 'POST', FullEndpointURL, 'Add Phone', Fields, FieldProperties) end If Error_Services('NoError') then // Serialize the JSON object. jsonResource = HTTP_Resource_Services('GetSerializedResource', objResource) // Set the response body with the serialized JSON object and set the Content-Type response header. HTTP_Services('SetResponseBody', jsonResource, False$, 'application/hal+json') end else // There is an error condition so call the SetResponseError service. HTTP_Services('SetResponseError', '', '', 500, Error_Services ('GetMessage'), FullEndpointURL) end end api |