Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect serialization of multiple-values options field when using GET method #103

Open
vierbergenlars opened this issue Sep 3, 2024 · 4 comments

Comments

@vierbergenlars
Copy link

When using a HAL-FORMS template with a property with options that allows multiple values to be selected, the values are incorrectly serialized to query parameters.

The multiple selected options are serialized as a single query parameter, separated by ,. According to the HAL-FORMS specification, each value must be serialized as separate query parameters: https://rwcbook.github.io/hal-forms/#options-return-values.

In this example, I have selected 2 items for the sort parameter. I was expecting the request URL to be /suppliers?sort=name,asc&sort=bank_account,asc, but it is incorrectly serialized as /suppliers?sort=name,asc,bank_account,asc

HAL-FORMS template for example
{
  "_templates": {
    "search": {
      "method": "GET",
      "properties": [
        {
          "name": "name",
          "prompt": "Name",
          "type": "text",
          "options": {
            "minItems": 0,
            "maxItems": 1,
            "inline": [
              "Xenit",
              "AB Inbev"
            ]
          }
        },
        {
          "name": "bank_account",
          "prompt": "Bank account",
          "type": "text"
        },
        {
          "name": "bank_account~ci",
          "type": "text"
        },
        {
          "name": "sort",
          "type": "text",
          "options": {
            "promptField": "prompt",
            "valueField": "value",
            "minItems": 0,
            "inline": [
              {
                "value": "name,asc",
                "prompt": "name ASC"
              },
              {
                "value": "name,desc",
                "prompt": "name DESC"
              },
              {
                "value": "bank_account,asc",
                "prompt": "bank_account ASC"
              },
              {
                "value": "bank_account,desc",
                "prompt": "bank_account DESC"
              }
            ]
          }
        }
      ],
      "target": "http://localhost:9000/suppliers"
    }
  }
} 

Screenshot from 2024-09-03 14-39-49

@toedter
Copy link
Owner

toedter commented Sep 4, 2024

Thx for reporting, I will take a look.

BTW, the spec says: the contents of the options.selectedValues array SHOULD be serialized as a set of repeating name/value pairs (not MUST), but I will check what I can do about it.

@vierbergenlars
Copy link
Author

(not MUST)

You're right, I did not quote the spec verbatim and did not intend my must as an RFC2119 keyword.

I think I have already been able to narrow the cause down to

this.newRequestUri += item.name + '=' + item.value;
, where an array of values is implicitly being stringified by Javascript (it automatically joins the array values with a , as separator).

It does not look like explicitly desired behavior, but more a side effect of item.value being either string or an array.

@toedter
Copy link
Owner

toedter commented Sep 13, 2024

I thought quit a lot about the topic, and I read the spec again, it says:


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


I interpret this that this serialization is only recommended when using POST with contentType application/x-www-form-urlencoded.

The spec does not say anything about GET. You will find implementations for both forms, and the semantics is depended on the implementation. There might be implementations that would not accept the same query parameter twice, or implementations that ignore every duplicate query parameter except the first or the last. There might also be implementation that merge all values of duplicated query parameters.

So I tend to leave the current implementation as it is.

@vierbergenlars
Copy link
Author

I tried to remain within the HAL-FORMS spec; but you're right that at the place I referenced, it is an example that pertains to POST requests.

However, upon re-reading Section 5.1 Encoding Request URLs, this explicitly pertains to the usage for methods without a body.

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.

(I edited HTML5MUT link to inline the reference)

The behavior of a plain HTML form is to repeat the parameter for every value (for example: https://codepen.io/vierbergenlars-the-sans/pen/YzoMOog)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants