You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/main/asciidoc/mediatypes.adoc
+127-21
Original file line number
Diff line number
Diff line change
@@ -320,12 +320,35 @@ identically to <<mediatypes.hal,HAL documents>>.
320
320
HAL-FORMS allows to describe criterias for each form field.
321
321
Spring HATEOAS allows to customize those by shaping the model type for the input and output types and using annotations on them.
322
322
323
+
Each template will get the following attributes defined:
324
+
325
+
.Template attributes
326
+
[options="header", cols="1,4"]
327
+
|===============
328
+
|Attribute|Description
329
+
|`contentType`| The media type expected to be received by the server. Only included if the controller method pointed to exposes a `@RequestMapping(consumes = "…")` attribute, or the media type was defined explicitly when setting up the affordance.
330
+
|`method`| The HTTP method to use when submitting the template.
331
+
|`target`| The target URI to submit the form to. Will only be rendered if the affordance target is different than the link it was declared on.
332
+
|`title`| The human readable title when displaying the template.
333
+
|`properties`| All properties to be submitted with the form (see below).
334
+
|===============
335
+
336
+
Each property will get the following attributes defined:
337
+
338
+
.Property attributes
323
339
[options="header", cols="1,4"]
324
340
|===============
325
341
|Attribute|Description
326
342
|`readOnly`| Set to `true` if there's no setter method for the property. If that is present, use Jackson's `@JsonProperty(Access.READ_ONLY)` on the accessors or field explicitly. Not rendered by default, thus defaulting to `false`.
327
343
|`regex`| Can be customized by using JSR-303's `@Pattern` annotation either on the field or a type. In case of the latter the pattern will be used for every property declared as that particular type. Not rendered by default.
328
344
|`required`| Can be customized by using JSR-303's `@NotNull`. Not rendered by default and thus defaulting to `false`. Templates using `PATCH` as method will automatically have all properties set to not required.
345
+
|`max`| The maximum value allowed for the property. Derived from Hibernate Validator's `@Range` or JSR-303's `@Max` annotations.
346
+
|`maxLength`| The maximum length value allowed for the property. Derived from Hibernate Validator's `@Length` annotation.
347
+
|`min`| The minimum value allowed for the property. Derived from Hibernate Validator's `@Range` or JSR-303's `@Min` annotations.
348
+
|`minLength`| The minimum length value allowed for the property. Derived from Hibernate Validator's `@Length` annotation.
349
+
|`prompt`| The user readable prompt to use when rendering the form input. For details, see <<mediatypes.hal-forms.i18n.prompts>>.
350
+
|`placeholder`| A user readable placeholder, to give an example for a format expected. The way of defining those follows <<mediatypes.hal-forms.i18n.prompts>> but uses the suffix `_placeholder`.
351
+
|`type`| The HTML input type derived from the explicit `@InputType` annotation, JSR-303 validation annotations or the property's type.
329
352
|===============
330
353
331
354
For types that you cannot annotate manually, you can register a custom pattern via a `HalFormsConfiguration` bean present in the application context.
@@ -351,6 +374,7 @@ This setup will cause the HAL-FORMS template properties for representation model
351
374
HAL-FORMS contains attributes that are intended for human interpretation, like a template's title or property prompts.
352
375
These can be defined and internationalized using Spring's resource bundle support and the `rest-messages` resource bundle configured by Spring HATEOAS by default.
353
376
377
+
[[mediatypes.hal-forms.i18n.template-titles]]
354
378
==== Template titles
355
379
To define a template title use the following pattern: `_templates.$affordanceName.title`. Note that in HAL-FORMS, the name of a template is `default` if it is the only one.
356
380
This means that you'll usually have to qualify the key with the local or fully qualified input type name that affordance describes.
<1> A global definition for the title using `default` as key.
368
-
<2> A global definition for the title using the actual affordance name as key. Unless defined explicitly when creating the affordance, this defaults to `$httpMethod + $simpleInputTypeName`.
392
+
<2> A global definition for the title using the actual affordance name as key. Unless defined explicitly when creating the affordance, this defaults to the name of the method that has been pointed to when creating the affordance.
369
393
<3> A locally defined title to be applied to all types named `Employee`.
370
394
<4> A title definition using the fully-qualified type name.
371
395
====
372
396
373
397
NOTE: Keys using the actual affordance name enjoy preference over the defaulted ones.
374
398
399
+
[[mediatypes.hal-forms.i18n.prompts]]
375
400
==== Property prompts
376
401
Property prompts can also be resolved via the `rest-messages` resource bundle automatically configured by Spring HATEOAS.
377
402
The keys can be defined globally, locally or fully-qualified and need an `._prompt` concatenated to the actual property key:
<1> We define a `birthdate` property of type `LocalDate`.
435
+
<2> We expect `ccn` to adhere to a regular expression.
436
+
<3> We define `email` to be an email using the JSR-303 `@Email` annotation.
437
+
438
+
Note that this type is not a domain type.
439
+
It's intentionally designed to capture a wide range of potentially invalid input so that potentialy erroneous valies for the fields can be rejected at once.
440
+
441
+
Let's continue by having a look at how a controller makes use of that model:
<1> A controller method is declared to use the representation model defined above to bind the request body to if a `POST` is issued to `/customers`.
468
+
<2> A `GET` request to `/customers` prepares a model, adds a `self` link to it and additionally declares an affordance on that very link pointing to the controller method mapped to `POST`.
469
+
This will cause an <<server.affordances, affordance model>> to be built up, which -- depending on the media type to be rendered eventually -- will be translated into the media type specific format.
470
+
471
+
Next, let's add some additional metadata to make the form more accessible to humans:
472
+
473
+
.Additional properties declared in `rest-messages.properties`.
<1> We define an explicit title for the template created by pointing to the `createCustomer(…)` method.
481
+
<2> We explicitly a prompt and placeholder for the `ccn` property of the `CustomerRepresentation` model.
482
+
483
+
If a client now issues a `GET` request to `/customers` using an `Accept` header of `application/prs.hal-forms+json`, the response HAL document is extended to a HAL-FORMS one to include the following `_templates` definition:
484
+
485
+
[source, json]
486
+
----
398
487
{
399
488
…,
400
489
"_templates" : {
401
-
"default" : {
402
-
"title" : "Create employee",
403
-
"method" : "put",
404
-
"contentType" : "",
490
+
"default" : { <1>
491
+
"title" : "Create customer", <2>
492
+
"method" : "post", <3>
405
493
"properties" : [ {
406
-
"name" : "firstName",
407
-
"prompt" : "Firstname",
408
-
"required" : true
409
-
}, {
410
-
"name" : "lastName",
411
-
"prompt" : "Lastname",
412
-
"required" : true
413
-
}, {
414
-
"name" : "role",
415
-
"prompt" : "Role",
416
-
"required" : true
417
-
} ]
494
+
"name" : "name",
495
+
"required" : true,
496
+
"type" : "text" <4>
497
+
} , {
498
+
"name" : "birthdate",
499
+
"required" : true,
500
+
"type" : "date" <4>
501
+
} , {
502
+
"name" : "ccn",
503
+
"prompt" : "Credit card number", <5>
504
+
"placeholder" : "1234123412341234" <5>
505
+
"required" : true,
506
+
"regex" : "[0-9]{16}", <6>
507
+
"type" : "text"
508
+
} , {
509
+
"name" : "email",
510
+
"prompt" : "Email",
511
+
"required" : true,
512
+
"type" : "email" <7>
513
+
} ]
418
514
}
419
515
}
420
516
}
421
517
----
422
-
====
518
+
<1> A template named `default` is exposed. Its name is `default` as it's the sole template defined and the spec requires that name to be used.
519
+
If multiple templates are attached (by declaring additional affordances) they will be each named after the method they're pointing to.
520
+
<2> The template title is derived from the value defined in the resource bundle. Note, that depending on the `Accept-Language` header sent with the request and the availability different values might returned.
521
+
<3> The `method` attribute's value is derived from the mapping of the method the affordance was derived from.
522
+
<4> The `type` attribute's value `text` is derived from the property's type `String`.
523
+
The same applies to `birthdate` property, but resulting in `date`.
524
+
<5> The prompt and placeholder for the `ccn` property are derived from the resource bundle as well.
525
+
<6> The `@Pattern` declaration for the `ccn` property is exposed as `regex` attribute of the template property.
526
+
<7> The `@Email` annotation on the `email` property has been translated into the corresponding `type` value.
527
+
528
+
HAL-FORMS templates are considered by e.g. the https://github.com/toedter/hal-explorer[HAL Explorer], which automatically renders HTML forms from those descriptions.
0 commit comments