Passing multipart/form-data to file service via API

community

#1

API Version: 2.3.0

Ulitmate goal is to record a file being uploaded to the database, then store that file in S3 using the following format: {s3bucket}/application/{table_record_primary_key}/{filename}

This is the process I am planning:

  1. Form posts required file & field data using multipart/form-data Content-Type.
  2. In Pre-Process POST script for the table, I check that the files array exists within the $_FILES array.
  3. In Post-Process POST script for the table, I want to upload using an internal API call to the S3 File Service.

I’ve found that if I add the folder and file structure as the payload, then it’ll create an empty folder, but a file is never created. I do see the FILE array exists in the pre-process script for the S3 File Service. I’ve also found that if I base64_encode the file, it’ll allow me to upload it, but with large files, this can be a resource hog.

I’m looking for help on how to pass the file post data from the original request, along with the resource ID of the inserted record over to the S3 Files Service so that a directory is created, then the binary file is added to that directory.

Thanks in advance for your help.


#2

I have since found a solution. Please provide any tips or advice to improve, I’m fairly new, but have spent the last 2 days researching and troubleshooting this. I have the following set up:

ON THE CLIENT:
Post URL: /tableService/_table/tableName
Post Data:
Form method: multipart/form-data
-You have to provide each of your table fields as a form key:value pair
-You have to provide the upload file with a key of “files
-You also need your authentication headers (X-DreamFactory-Session-Token & X-Dreamfactory-API-Key)

ON THE SERVER SIDE
You’ll need to set up a pre and post process script for the table.

…pre_process
tableService._table.tableName.post.pre_process

if(!isset($_FILES['files']) || !is_array($_FILES['files'])){
        // Stop execution and return a specific status code
        $event['response']['errorCode'] = 400;
        $event['response']['errorMessage'] = "File is missing. Check that the a file was provided and the field name is: [files], to continue.";
        return false;
    } else {
        $event['payload'] = $_POST;
        // use this next variable if your table has a field, "fileName" to store the file name. This should be changed to your needs
        $event['payload']['fileName'] = $_FILES['files']['name'];
        $event['payload'] = array("resource"=>array($event['payload']));
        $event['request']['payload'] = $event['payload'];
        $event['request']['content'] = json_encode($event['payload']);
        $event['request']['content_type'] = 'json';
    }

From here, the table should add the record, we’ll handle uploading the file in the post_process script for the table.

…post_process
tableService._table.tableName.post.post_process

// we need to get the ID of the created record. Be sure to use the variable you want to use as your ID.
$recordId = $r['primaryKeyId'];

// For path, you can prepend an already existing directory if you need to like this.
$path = '/Documents/'.$recordId;

// The filename should be in the returned resource, assuming you store it. Otherwise, you can pull this from the $_FILES array, if you haven't changed it from the POST'd value. We should only have one file, so we'll use resource 0.
$filename = $event['payload']['resource'][0]['fileName'];

/**
 * Prepping file for upload via API Endpoint
 */

// This is the URL for your internal files API Endpoint
$url = 'fileService/'.$path;

// let's create the directory, we need to make sure there is a trailing slash
$post($url.'/');

// we need to read the file data into a string, so we'll use file_get_contents on the tmp file.
$fileData = file_get_contents($_FILES['files']['tmp_name']);

$post($url.'/'.$filename, $fileData);