0

I am working with a custom REST class that accepts @HttpPost requests. The main problem that I am facing is that when the content-type of the incoming request is set to application/x-www-form-urlencoded, the values coming from the multi-select picklist are lost.

As per Salesforce documentation, usually REST request is stored in RestRequest.requestBody attribute. However, because Salesforce is able to parse application/x-www-form-urlencoded request, it assigns all values into the RestRequest.params map and leaves requestBody attribute blank. Unless Javascript is used to manipulate the information on the basic html form, the encoded data will look like

myMultiselectPicklist=value1&myMultiselectPicklist=value2&myMultiselectPicklist=value3&...

So I have the following questions:

  1. Is this the expected behaviour?
  2. What are my options of retrieving all values from the request without modifying the html form?

Test Code

Here is a sample html form that I use for testing this behaviour:

<!doctype html>
<html lang="">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        <title>Test Form</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
        <!--[if lte IE 9]>
            <p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience and security.</p>
        <![endif]-->

        <!-- Add your site or application content here -->
        <p>Test Form</p>
        <form action="https://bcstest-developer-edition.eu5.force.com/rest/services/apexrest/bcs_test/test/123" method="post" enctype="application/x-www-form-urlencoded">
            <select name="cars" multiple>
              <option value="volvo">Volvo</option>
              <option value="saab">Saab</option>
              <option value="opel">Opel</option>
              <option value="audi">Audi</option>
            </select>
            <textarea name="description"></textarea>
            <input type="submit" value="Submit" />
        </form>

    </body>
</html>

Code for the apex class:

    // test url: https://bcstest-developer-edition.eu5.force.com/rest/services/apexrest/test/123
@RestResource(urlMapping='/test/*')
global with sharing class TestPublicRest {
    @HttpGet    
    global static void doGet() {
        RestContext.response.headers.put('Content-Type','text/html');
        RestContext.response.statusCode = 200;
        RestContext.response.responseBody = Blob.valueOf('<html><body style="color:red">Hello World</body>' + RestContext.request.requestBody + '</html>');
    }

    @HttpPost   
    global static void doPost() {
        RestContext.response.headers.put('Content-Type','text/html');
        RestContext.response.statusCode = 200;
        List<String> items = new List<String>();
        for(String key : RestContext.request.headers.keySet()) {
            items.add(key + ' => ' + RestContext.request.headers.get(key));
        }
        RestContext.response.responseBody = Blob.valueOf('<html><body><span>Headers</span><div>' + String.join(items,'<br/>') + '</div><br/><br/><span>Request Body</span><div>' + EncodingUtil.urlEncode(RestContext.request.requestBody.toString(), 'utf-8') + '</div><br/><br/><span>Params</span><div>' + RestContext.request.params + '</div></body></html>');
    }
}
1

Is this the expected behaviour?

Yes, this is a limitation of the system's parameter handling mechanism.

What are my options of retrieving all values from the request without modifying the html form?

You'll have to parse it manually using RestContext.request.requestBody. Something like this:

String[] uriParts = RestContext.request.requestBody.split('\\?');
Map<String, String[]> params = new Map<String, String[]>();
if(uriParts.size() == 2) {
  for(String nameValuePair: uriParts[1].split('&')) {
    String[] nameValue = nameValuePair.split('='), temp = params.get(nameValue[0].toUpperCase());
    if(temp == null) {
      // Following line uses inline assignment to save CPU time
      params.put(nameValue[0].toUpperCase(), temp = new String[0]);
    }
    temp.add(EncodingUtil.urlDecode(nameValue[1], 'utf-8'));
  }      
}

At the end of this code, params will contain the name values in uppercase, with a list of values for each.

Edit: Noticed it should be the requestBody, not requestURI. The answer remains the same, however.

  • Unfortunately the requestBody is empty when the system parses the key-value pairs into the params attribute. – Artur Apr 28 '17 at 12:39
  • @Artur Yeah, I checked that and came to the same conclusion. There's supposed to be a way to do ths, but the docs don't make it obvious. I'll keep looking. – sfdcfox Apr 28 '17 at 15:22
  • So far I looks through all parameters and have not found a way to parse the values correctly. I don't think there is a way to instruct Salesforce not to parse the request, is there? – Artur Apr 29 '17 at 15:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.