In MivaScript, the MvCALL tag is the way to have your script communicate with an external server. When coding modules for Miva Merchant, the shopping cart, this is used for any number of reasons. Some of the most common communications are:
- getting shipping rates from a carrier API, such as UPS, FedEx, or USPS
- processing credit cards through a payment gateway
- passing order details to an order management system (OMS)
I’ve been doing a lot of integration work lately between Miva Merchant and third-party systems. Many times, it’s a simple GET or POST request. But sometimes, various quirks in MivaScript mean we have to use the RAW method within the MvCALL tag instead.
Here are two of those reasons that I’ve run across since I’ve been coding MivaScript.
1. Passing data via MvCALL that isn’t name/value pairs, such as JSON or XML
Most of the time, when we call another URL, we want to send data to it. With the GET method, we can use name/value pairs in the querystring (part of the URL). With the POST method, we can send data in name/value pairs in the FIELDS attribute.
However, not every service expects name/value pairs. Often, we need to send XML or JSON directly to the server we’re calling as part of the request body.
Let’s say we are posting the following JSON that we currently have stored in a variable called l.jsonrequest. It looks like this:
{"shopperName":"John Doe","basketSubtotal":24.99}
If we were to send this using POST, it would be sent as a name value pair, using the variable name as the “name” portion:
jsonrequest={"shopperName":"John Doe","basketSubtotal":24.99}
But if the server expects only the JSON, that won’t work. This is where we use the RAW method. The call looks like this:
<MvCALL ACTION="{ l.url }"
CONTENT-TYPE="application/json"
METHOD="RAW"
FIELDS="l.jsonrequest">
When we do this, the fields specified in the FIELDS attribute are not transformed into name/value pairs. They are just sent as raw data.
The CONTENT-TYPE attribute is also important. If it’s not specified, the RAW method will send CONTENT-TYPE of “text/plain”. If the server expects JSON, you likely need to tell it that the data you’re sending is JSON, by setting the CONTENT-TYPE to application/json.
If you want to post XML, it would use the same format, but the CONTENT-TYPE would be set to “text/xml”. Here’s an example, assuming that the XML is stored in a variable called l.xmlrequest.
<MvCALL ACTION="{ l.url }"
CONTENT-TYPE="text/xml"
METHOD="RAW"
FIELDS="l.xmlrequest">
Here’s another tip on using JSON with MvCALL. MivaScript will generate an error if an endpoint returns JSON that contains a less-than symbol. To handle this, Miva has added a noparse flag. You can see more about this here.
2. Passing name/value pairs over MvCALL that cannot be defined in MivaScript
I’ve also run into two cases where I needed to pass name/value pairs, but they were variables that can’t exist in MivaScript. One case was where I had to send a list of products as a 0-based array. However, MivaScript is a language where everything is 1-based.
By way of explanation, in a 0-based language, a 5-element array with no empty spaces would have data in positions 0 through 4. That’s still 5 elements: positions 0, 1, 2, 3 and 4.
However, in a 1-based language, the same array would have data in positions 1-5.
This particular service expected the index to start with 0. There’s no way in MivaScript to make this kind of assignment:
<MvASSIGN NAME="l.productarray" INDEX="0" VALUE="{ 'abc123' }">
<MvASSIGN NAME="l.productarray[0]" VALUE="{ 'abc123' }">
Both of these statements generate a compile-time error, because an array can’t have an index of 0.
To compensate in this case, you can build the name/value pairs in a string, like this:
<MvASSIGN NAME="l.fields" VALUE="{ 'productarray[0]=abc123&productarray[1]=xyz789' }">
And then you can call the endpoint using the RAW method:
<MvCALL ACTION="{ l.url }"
CONTENT-TYPE="application/x-www-form-urlencoded"
METHOD="RAW"
FIELDS="l.fields">
Here, you must set CONTENT-TYPE explicitly again. The value “application/x-www-form-urlencoded” is what indicates name/value pairs.
The same service had a different endpoint that required an array with a non-numeric index. This is another construct that isn’t supported in MivaScript. The following assignments both fail because ‘sku’ is invalid, since it’s not numeric. (It could be used as a member name, but not an index.)
<MvASSIGN NAME="l.productarray" INDEX="sku" VALUE="{ 'abc123' }">
<MvASSIGN NAME="l.productarray['sku']" VALUE="{ 'abc123' }">
The same kind of construct as above still works:
<MvASSIGN NAME="l.fields" VALUE="{ 'productarray['sku']=abc123' }">
Likewise, the MvCALL will be the same as when passing a 0-based array.