restfile-uploadcoldfusioncoldfusion-11

Upload File with Meta-Data (`multipart/form-data`) to ColdFusion 11 REST Service


How do you access meta-data (form data) sent with a file upload (using enctype="multipart/form-data") in a ColdFusion 11 REST Service?

Mocking up a simple service:

component
  restpath = "test"
  rest     = true
{
  remote void function upload(
    required numeric id       restargsource = "Path",
    required any     document restargsource = "Form",
    required string  title    restargsource = "Form"
  )
    httpmethod = "POST"
    restpath   = "{id}/"
    produces   = "application/json"
  {
    if ( FileExists( document ) )
      restSetResponse({
        "status"  = 201,
        "content" = {
          "id"    = id,
          "title" = title,
          "size"  = GetFileInfo( document ).size
        }
      });
    else
      restSetResponse({
        "status"  = 400,
        "content" = "Nothing uploaded"
      });
  }
}

and a simple HTML file to test it:

<!DOCTYPE html>
<html>
<body>
<form method="post"
      action="http://localhost/rest/TestService/test/1/"
      enctype="multipart/form-data">
<input type="text" name="title"    value="File Title" /><br />
<input type="file" name="document" /><br />
<button type="submit">Submit</button>
</form>
</body>
</html>

Then the service returns a 500 HTTP status code and the JSON response:

{"Message":"The DOCUMENT parameter to the upload function is required but was not passed in."}

Checking the HTTP request headers shows that both fields were passed in but the service is not receiving them.

Commenting out the enctype attribute within the HTML form (so it uses the default encoding of application/x-www-form-urlencoded) then the service returns a 400 HTTP status code and the response Nothing uploaded.

How can this be resolved?


Solution

  • To be thoroughly confusing the request data populates the FORM variable but, even though the function arguments state restargsource="form", the value is not passed on to the REST service as its argument when the enctype is anything other than application/x-www-form-urlencoded.

    This is confirmed in Adobe's Getting started with RESTful web services in ColdFusion article:

    Form parameters:

    In many scenarios, you must process data that you enter in the form in a REST service. You can use this data to make a new entry ( POST ) or update an existing record ( PUT ) in the database. If you use form fields, set restargsource to form . This extracts the data present in the request and makes it available for further processing. Also, you must set the content-type header to application/x-www-form-urlencoded when sending data as form fields.

    However, it can be solved by changing the arguments which would use restargsource="form" to be parameters explicitly scoped within the form variable.

    So, the modifying the service like this:

    component
      restpath = "test"
      rest     = true
    {
      remote void function upload(
        required numeric id       restargsource = "Path"
      )
        httpmethod = "POST"
        restpath   = "{id}/"
        produces   = "application/json"
      {
        param name="form.document" type="string";
        param name="form.title"    type="string";
    
        if ( FileExists( form.document ) )
          restSetResponse({
            "status"  = 201,
            "content" = {
              "id"    = id,
              "title" = form.title,
              "size"  = GetFileInfo( form.document ).size
            }
          });
        else
          restSetResponse({
            "status"  = 400,
            "content" = "Nothing uploaded"
          });
      }
    }