Creating a RESTful API to accept a Multipart Form Post

Creating a RESTful API to accept a Multipart Form Post

Today, we encountered an unusual requirement. Someone needed to send a file via API using Multipart Form Data, rather than Base64 encoding the file and submitting it as JSON data. I have experience sending files using Multipart Form Data, both via the HTTPSendForm function and by manually encoding the data using our wxHTTP class. I’ve also sent and received files by encoding them into JSON data using Base64. However, I had not yet received files via Multipart Form Data.

A little background

One could argue that Multipart Form Data performs better, particularly for large files. However, a downside is that the submission format differs from the rest of your API. This is especially relevant if your API is a modern RESTful/JSON API.

Form-encoded data might be familiar to you. It’s not significantly different from URL-encoded data, except that it’s sent as the body of a POST request instead of being part of the URL in a POST or GET request. The Content-Type header is “application/x-www-form-urlencoded” and the body of the POST request might look something like this.

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo

If you put a question mark in front of that, it would be URL encoded.

Meanwhile, Multipart Form Data is a significantly more complex format. The Content-type is multipart/mixed; boundary=”xxxx”. This “xxxx” is a random string you choose to act as a delimiter for the different fields in your data. However, this presents the first complication. If your data happens to contain this text, your post will not function properly. Therefore, in a real-world example, you would use something more discrete than “xxxx”. The body would look similar to this:

--xxxx
Content-Disposition: form-data; name="MyVariableOne"

ValueOne
--xxxx
Content-Disposition: form-data; name="MyVariableTwo"

ValueTwo

Parsing and using such data can be complex. This is why Multipart Data is typically only used when file uploads are involved. If you were to include a file in the Multipart Form Data of our above example, it would look something like this.

--xxxx
Content-Disposition: form-data; name="MyVariableOne"

ValueOne
--xxxx
Content-Disposition: form-data; name="MyVariableTwo"

ValueTwo
--xxxx
Content-Disposition: form-data; name="logo" filename="wxPertslogo.png"
Content-Type: image/png

[***the cotent of wxPertslogo.png would be here**]

Create a RESTful procedure in WINDEV or WEBDEV

Now that we’ve covered the complex details and inner workings, let me reassure you. PCSOFT has streamlined this process by handling all the decoding and parsing for us. In our REST procedure, we simply need to refer to the first two variables by name.

MyVariableOne = WebserviceParameter("MyVariableOne")
MyVariableTwo = WebserviceParameter("MyVariableTwo")

They’ve already handled a lot of the heavy lifting for us. However, I still prefer to receive JSON data that I can manage as complex structured data. But let’s not digress, as that’s not the focus of this article. 🙂

But how do we manage the actual file? I confess, I initially overthought this due to knowing the complexity of the underlying task. However, it’s quite straightforward. When the Web Application Server (WAS) processes the Multipart form data, it creates a variable akin to the first two. But in this case, it includes two pieces of information separated by a semicolon.

The first portion is the actual filename submitted, while the second portion is the complete directory and filename where the WAS has saved the file’s contents.

So, if we were to do something like this

FileInfo = WebserviceParameter("logo")

The contents of FileInfo would resemble the following.

logo.jpg;C:\\WEBDEV\\TmpUpload\\WEBDEV_0_5872_3983841659_31112057_0.upl

All we need to do is copy that file to the required location and give it the appropriate filename, or whatever your processing needs dictate.

Creating the Procedure

Let’s integrate everything within a WL REST Procedure.

PROCEDURE MultiFormTest()

MyVariableOne  is string = WebserviceParameter("MyVariableOne")
WriteLog(MyVariableOne)

MyVariableTwo  is string = WebserviceParameter("MyVariableTwo")
WriteLog(MyVariableTwo)

FileInfo is string = WebserviceParameter("logo")
WriteLog(FileInfo)

RealFileName is string = ExtractString(FileInfo,1,";")
TempFile is string =  ExtractString(FileInfo,2,";")
WriteLog(RealFileName)
WriteLog(TempFile)

NewFile is string = "C:\\temp\\"+RealFileName
WriteLog(NewFile)

fCopyFile(TempFile,NewFile)

Writelog is a simple procedure used to write information into a text log for debugging. It serves as our main method for debugging REST procedures.

Lines 3, 6, and 9 retrieve the values as previously discussed.

Lines 12 and 13 use another excellent WL function to separate FileInfo into two distinct fields.

In line 17, we construct the new file name, utilizing the directory where we want to place the file and the original file name as submitted. Clearly, this isn’t production-ready code, and you would need to carry out considerable pre and post processing of the file before directly writing it to your server.

Finally, line 20 copies the temporary file to the new file name and location.

We don’t need to delete the temporary file. The WAS does it for us once the procedure is complete.

The only step left is to create an endpoint in our REST API, as follows:

Note that the request format is HTML form and the method is POST.

Testing the procedure

We can create simple code to test our new REST procedures as follows:

HTTPCreateForm("myform")
HTTPAddParameter("myform","MyVariableOne","ValueOne")
HTTPAddParameter("myform","MyVariableTwo","ValueTwo")
HTTPAddFile("myform","logo","C:\\temp\\wxPertslogo.png")
HTTPSendForm("myform","<http://resttest.wxperts.com/MultiFormTest>",httpPost)

If we execute this code and then check the server, our REST log will contain the following information.

20240610181310894-ValueOne
20240610181310894-ValueTwo
20240610181310894-wxPertslogo.png;C:\\WEBDEV\\TmpUpload\\WEBDEV_0_8868_3272774629_31112075_0.upl
20240610181310894-wxPertslogo.png
20240610181310894-C:\\WEBDEV\\TmpUpload\\WEBDEV_0_8868_3272774629_31112075_0.upl
20240610181310894-C:\\temp\\wxPertslogo.png

Sure enough, if we look in the C:\temp directory, our logo is there.

Leave a comment