Invoke multipart REST API to upload file

Overview

The service API executable supports only XML and JSON payloads and therefore cannot invoke APIs that require the multipart/form-data content type for file uploads.

To upload files to such APIs, use the FILE_UPLOAD executable together with a Groovy script. The Groovy script performs the HTTP multipart request while the FILE_UPLOAD executable manages the upload lifecycle.

Prerequisite

The groovy-wslite-1.1.3.jar library must be available on the classpath. To install,

  1. Copy groovy-wslite-1.1.3.jar to ria-dmi/lib.
  2. Restart the DOH processes. Once restarted, the Groovy script can import and use the wslite.rest package.

Configure the executable

Configure a DOH task that uses a FILE_UPLOAD executable.

Parameters

Parameter Description
fileFormat Must be set to GROOVY to indicate that the upload is controlled by a custom Groovy script.
filePath Full path of the file to upload.
skipGroovyCompile

If set to false, the script is compiled when saved. Regardless of this setting, the RuntimeServer always compiles and parses the script at execution time.

Mandatory: No
Default: false

tableName

Specify a valid database table such as DUAL. No records are inserted because the Groovy script returns null.

Mandatory: Yes

url Custom parameter containing the target API endpoint that receives the multipart upload.

Groovy script

The task’s data block contains the Groovy script. The script must begin with groovy = because it is stored as the value of the groovy parameter in the task’s Data block.

If the script is placed in a custom FILE_UPLOAD executable instead, omit the groovy = prefix.

groovy =

import wslite.rest.*

class MultiPartUpload {

    TaskWorkExecutorParameters parameters
    File file

    def startUpload(TaskWorkExecutorParameters parameters) {
        // ---------------------------------------------------------------------------------------------
        // Start of file upload. Perform initialization before upload starts.
        // Parameters contain all runtime parameters (filePath, csvDelimiter, etc.)
        // as well as any custom parameters.
        //
        // Common methods:
        //   String getRequiredStringParameterValue(String parameterId);
        //   String getOptionalStringParameterValue(String parameterId, String defaultValue);
        //   String getNullableStringParameterValue(String parameterId);
        //   Integer getIntegerParameterValue(String parameterId, Integer defaultValue);
        //   Boolean getBooleanParameterValue(String parameterId);
        //   Boolean getBooleanParameterValue(String parameterId, Boolean defaultValue);
        //   Boolean hasParameterValue(String parameterId);
        // ---------------------------------------------------------------------------------------------
        this.parameters = parameters
    }

    def startFile(File file) {
        // ---------------------------------------------------------------------------------------------
        // Called when a new file is about to be processed.
        //
        // Perform any initialization here, such as opening files,
        // creating counters, or allocating resources.
        //
        // Return true to process the file or false to reject it.
        // ---------------------------------------------------------------------------------------------
        this.file = file
        return true
    }

    def hasMoreData(int recordIndex) {
        // ---------------------------------------------------------------------------------------------
        // Called repeatedly by the FILE_UPLOAD process.
        //
        // Returning true causes buildRecords() to be called.
        // Returning false ends the upload.
        //
        // This implementation returns true only once so the file
        // is uploaded a single time.
        // ---------------------------------------------------------------------------------------------
        return recordIndex == 0
    }

    def buildRecords(int recordIndex) {
        // ---------------------------------------------------------------------------------------------
        // Performs the multipart upload.
        //
        // Returning null tells FILE_UPLOAD that there are no database
        // records to insert and ends processing.
        // ---------------------------------------------------------------------------------------------

        String url = parameters.getRequiredStringParameterValue('url')

        ThreadLogger.logInfo('Accepted parameter url: %s', url)

        RESTClient client = new RESTClient(url)

        client.httpClient.sslTrustAllCerts = true

        def bytes = file.bytes

        def response = client.post {
            multipart 'file', bytes, 'text/plain', file.name
        }

        // Return null so the framework does not upload data
        // into the configured database table.
        return null
    }
}