This demonstrates uploading an image using multipart/form-data via an input stream passed to qie.callRESTWebService().
//Get an uuid to make the boundary and file names unique.
var uuid = qie.getUUID();
//Create a temporary file for the multipart content.
var multipartFileName = "request_" + uuid + ".tmp";
var multipartFilePath = "/tmp/" + multipartFileName;
//The image to add to the content
var imageName = "dog.jpeg";
var imagePath = "/Users/dir/Pictures/" + imageName;
//The name of the multipart boundary
var boundary = "myBoundary-" + uuid;
//Set the Content-Type to multipart/form-data and specify the boundary
var requestContentType = "multipart/form-data; boundary=" + boundary;
// Create a new parameter map. This would be used to add headers to the request.
var parameterMap = qie.newParameterMap();
// For this exaple no headers are needed. If required they would be added with the "http.header." prefix. Example:
// parameterMap.put("http.header.headerName", "value");
//Build the content without looading all the bytes into memory.
var outputStream = new java.io.FileOutputStream(multipartFilePath);
// Write begining of first boundary.
// NOTE: must start with two dashses and end with a new line "\r\n"
var openBoundary = "--" + boundary + "\r\n";
//Add headers for the part. NOTE: we do NOT need the "http.header." prefix when adding headers to a part.
//This is added to indicate to the server the form field (favoriteAnimal) and the filename being uploaded (dog.jpeg)
openBoundary += "Content-Disposition: form-data; name=\"favoriteAnimal\"; filename=\"" + imageName + "\"\r\n";
//Since this example uses a stream vs. a string, this header is not needed.
//openBoundary += "encoding: ISO-8859-1\r\n";
//The server used for this example is a QIE HTTP Listener. Which handles multipart content with a boundary when streaming. However, other servers may require it.
//openBoundary += "content-transfer-encoding: binary\r\n";
openBoundary += "Content-Type: image/jpeg\r\n";
//Write the openBoundary to the output stream.
outputStream.write((new java.lang.String(openBoundary)).getBytes());
//Add a blank line before we write the image data to the part.
outputStream.write((new java.lang.String("\r\n")).getBytes());
//Stream the image to the outputStream
var inputStream = new java.io.FileInputStream(imagePath);
// The size of a chunk to copy at a time.
var chunkSize = 1024;
//Creates a new byte[] to store a chunk in.
var chunkByteArray = new Packages.java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, chunkSize);
//This is the number of bytes read by calling inputStream.read.
//Used to tell when there are no more bytes to read.
var bytesRead;
while ((bytesRead = inputStream.read(chunkByteArray)) != -1) {
//Write the chunk to the outputStream.
outputStream.write(chunkByteArray, 0, bytesRead);
}
//Close image boundary
var closeBoundary = "\r\n--" + boundary + "--\r\n";
outputStream.write((new java.lang.String(closeBoundary)).getBytes());
//Close the input and output streams
inputStream.close();
outputStream.flush();
outputStream.close();
// Open the multipart file (saved above) as a stream.
var contentInputStream = java.io.FileInputStream(multipartFilePath);
//URL template for the endpoint. This is used to override the endpoint in the web service connection.
var urlTemplate = qie.evaluateTemplate("http://localhost:8083/streamUploadImageFileInMultipartFormData");
//Call a REST web service using the provided parameters
var result = qie.callRESTWebService(
"wsName",
urlTemplate,
"POST",
contentInputStream,
requestContentType,
parameterMap,
60000);
//Cache the response for further processing later.
messageCache.setValue("restResult", result);
//Delete the temporary file
qie.deleteFile(multipartFilePath);
let's take a closer look:
Unique Identifiers (UUID):
- This ensures the filenames and boundaries are unique. To avoid potential conflicts or overwrites when handling multiple requests.
-
File Paths:
- The temporary file path (
multipartFilePath
) stores the constructed multipart message before uploading. It acts as a staging area for the message before sending it.
- The image path (
imagePath
) is the location of the image file to include in the multipart message.
-
Multipart Parameters:
- Boundary: Multipart content consists of multiple parts separated by a boundary. The receiving server relies on this boundary to identify and process each part (only one part containg image data in this case). Setting a unique boundary ensures proper delineation between parts.
- Content-Type: Informs the server that the message body is multipart and specifies the boundary string used for separation.
-
Building Multipart Content:
- Temporary File: This file holds the constructed multipart message with the image data before sending it as a whole.
- Opening Boundary: Signals the beginning of a part within the multipart message. The specific format with double dashes and a newline is essential for the server to recognize it.
- Image Part Headers:
Content-Type: image/jpeg
- Identifies the content as a JPEG image.
Content-Disposition: form-data; name="petField" filename="dog.jpeg"
(Required) - Provides additional metadata about the content being transmitted (form field and filename)
- Writing Image Data: Reads the image file in chunks for efficiency and writes it to the temporary file containing the multipart message.
- Closing Boundary: Signals the end of the image part within the multipart message. The format again follows a specific pattern for proper recognition by the server.
-
Uploading Multipart Message:
- Opening Multipart File Stream: The temporary file with the complete multipart message is opened as a stream for efficient transmission. This avoids loading the entire content into memory at once.
- Web Service URL Template: Defines the endpoint where the web service expects to receive the multipart upload.
- Uploading the Stream: The content stream (
contentInputStream
) containing the multipart message is sent to the web service using a POST request (common for uploads).
- Storing the Response: Caching the response can be helpful if the response needs to be accessed multiple times in a later mapping funnction or mapping node.
-
Cleanup:
- Deleting Temporary File: Once the upload is complete, the temporary file is no longer needed.