Skip to content

Add support for HAL-FORMS #66

Open
@carlobeltrame

Description

@carlobeltrame

HAL is fundamentally a read-only technology. So far, we have allowed the users to perform their own custom write operations by specifying the HTTP method to use and constructing a payload in the right format manually ($post(...), $patch(...), ...). In ecamp3, the payload format, required fields, etc. are not documented at all for users of the API.

There have been some efforts to push the standard further, in order to allow the API to specify more accurately and in a standardized way, how the user can interact with it. The most prominent such evolution of HAL I found is HAL-FORMS. HAL-FORMS goes even further by specifying the crucial form elements in a user interface, with the ultimate goal that the frontend (or API client) of an application should not have to be redeployed when the API changes some fields. HAL-FORMS is adopted by Spring HATEOAS, although being marked as an unstable specification for the time being.

This sounds intriguing, but obviously comes with its own set of problems, at least in the realm of designing and customizing the look of the forms. But we could start by supporting _templates as specified in HAL-FORMS in a similar way to how we support $post etc.:
API response in HAL-FORMS format:

{
  id: 345,
  firstName: 'John',
  lastName: 'Doe',
  _links: {
    self: {
      href: '/api/users/345',
    },
  },
  _templates: {
    "edit" : {
      "title" : "Edit user",
      "target": "/api/users/345",
      "method" : "PATCH",
      "contentType" : "application/json",
      "properties" : [
        {"name" : "firstName", "required" : true, "value" : "John", "prompt" : "First name"},
        {"name" : "lastName", "required" : false, "value" : "Doe", "prompt" : "Last name"},
      ],
    },
  },
}

Frontend code that uses this data:

const user = this.api.get().users({ id: 345 })

// Proposal: Reference templates with a $ sign and the template key

// The next line will create a PATCH request to /api/users/345,
// with the payload { firstName: 'Jonathan' }
await user.$edit({ firstName: 'Jonathan' })

// The next line will create a PATCH request to /api/users/345,
// with the payload { firstName: 'Jonathan', lastName: 'Doe-Smith' }
// (because firstName is required)
user.$edit({ lastName: 'Doe-Smith' })

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions