Skip to main content

Overview

PromoStandards APIs return responses in XML format by default (SOAP protocol requirement). The SDK provides automatic conversion to JSON for easier JavaScript/TypeScript integration.

Choosing a Response Format

The SDK supports two response formats, controlled by the format parameter:
import { PromoStandards } from 'promostandards';

// JSON responses (default)
const jsonClient = new PromoStandards.Client({
  id: 'username',
  password: 'password',
  endpoints: [/* ... */],
  format: 'json' // Default
});

// XML responses
const xmlClient = new PromoStandards.Client({
  id: 'username',
  password: 'password',
  endpoints: [/* ... */],
  format: 'xml'
});

When to Use Each Format

JSON (Recommended)

  • Default and most convenient for JavaScript/TypeScript
  • Easy to work with in modern applications
  • Native JavaScript object manipulation
  • Ideal for most use cases

XML

  • When you need raw SOAP responses
  • Custom XML parsing requirements
  • Debugging or logging raw responses
  • Integration with XML-based systems

JSON Response Format (Default)

By default, the SDK automatically converts XML responses to JSON using the convertXMLtoJSON utility.

Example JSON Response

const client = new PromoStandards.Client({
  id: 'username',
  password: 'password',
  endpoints: [{
    type: 'ProductData',
    version: '2.0.0',
    url: 'https://api.supplier.com/ProductData'
  }],
  format: 'json'
});

const result = await client.productData.getProduct({
  productId: 'ABC123',
  localizationCountry: 'US',
  localizationLanguage: 'en'
});

// Result is a JavaScript object
console.log(result.Envelope.Body.getProductResponse);

Working with JSON Responses

// Access nested data easily
const productData = result.Envelope.Body.getProductResponse.Product;

console.log(productData.productId);        // 'ABC123'
console.log(productData.productName);      // 'Custom T-Shirt'
console.log(productData.Description);      // Product description

// Arrays are automatically handled
if (productData.ColorArray) {
  productData.ColorArray.forEach(color => {
    console.log(color.colorName, color.hex);
  });
}

XML Response Format

When format: 'xml' is specified, the SDK returns raw XML strings from the SOAP service:
const client = new PromoStandards.Client({
  id: 'username',
  password: 'password',
  endpoints: [/* ... */],
  format: 'xml'
});

const xmlResult = await client.productData.getProduct({
  productId: 'ABC123',
  localizationCountry: 'US',
  localizationLanguage: 'en'
});

// xmlResult is a string
console.log(typeof xmlResult); // 'string'

Example XML Response

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <ns:getProductResponse xmlns:ns="http://www.promostandards.org/WSDL/ProductDataService/2.0.0/">
      <Product>
        <productId>ABC123</productId>
        <productName>Custom T-Shirt</productName>
        <Description>High-quality cotton t-shirt</Description>
        <ColorArray>
          <Color>
            <colorName>Red</colorName>
            <hex>#FF0000</hex>
          </Color>
          <Color>
            <colorName>Blue</colorName>
            <hex>#0000FF</hex>
          </Color>
        </ColorArray>
      </Product>
    </ns:getProductResponse>
  </soap:Body>
</soap:Envelope>

XML to JSON Conversion Process

The SDK uses the convertXMLtoJSON utility (from Utils.ts:29-50) to transform XML responses:

Conversion Implementation

export const convertXMLtoJSON = (xml: string): Promise<any> => {
  return new Promise((resolve, reject) => {
    xml2js.parseString(
      xml,
      {
        explicitArray: false, // Only create arrays for multiple records
        ignoreAttrs: true,    // Ignore XML attributes
        tagNameProcessors: [xml2js.processors.stripPrefix], // Remove namespace prefixes
        valueProcessors: [
          xml2js.processors.parseNumbers,   // Convert numeric strings to numbers
          xml2js.processors.parseBooleans,  // Convert 'true'/'false' to booleans
        ],
      },
      (err: any, data: any) => {
        if (err) {
          reject(err);
        }
        resolve(replaceArrayTagsWithArrays(data));
      }
    );
  });
};

Conversion Features

XML namespaces are automatically removed for cleaner JSON keys:
<!-- XML with namespace -->
<ns:getProductResponse>
  <ns:Product>
    <ns:productId>ABC123</ns:productId>
  </ns:Product>
</ns:getProductResponse>
// JSON without namespace prefixes
{
  "getProductResponse": {
    "Product": {
      "productId": "ABC123"
    }
  }
}
String values are automatically converted to appropriate types:
<!-- XML strings -->
<quantity>100</quantity>
<available>true</available>
<price>29.99</price>
// JSON with native types
{
  "quantity": 100,        // number
  "available": true,      // boolean
  "price": 29.99          // number
}
The SDK intelligently handles arrays using two mechanisms:1. explicitArray: falseSingle items are NOT wrapped in arrays, multiple items are:
// Single color - not an array
{ "Color": { "colorName": "Red" } }

// Multiple colors - array
{ "Color": [{ "colorName": "Red" }, { "colorName": "Blue" }] }
2. Array Tag DetectionTags ending in “Array” are forced to arrays (Utils.ts:16-27):
export const replaceArrayTagsWithArrays = (obj: any) => {
  let key;
  if (obj instanceof Object) {
    for (key in obj) {
      if (obj.hasOwnProperty(key) && /.*Array/.test(key)) {
        obj[key] = ensureArray(skipLevel(obj[key]));
      }
      replaceArrayTagsWithArrays(obj[key]);
    }
  }
  return obj;
};
<!-- XML with Array tag -->
<ColorArray>
  <Color>Red</Color>
</ColorArray>
// Guaranteed to be an array
{
  "ColorArray": ["Red"]  // Always an array, even with one item
}
XML attributes are ignored by default (ignoreAttrs: true):
<!-- XML with attributes -->
<Product id="123" status="active">
  <productName>T-Shirt</productName>
</Product>
// Attributes are not included
{
  "Product": {
    "productName": "T-Shirt"
  }
}
PromoStandards rarely uses XML attributes, so this simplifies the JSON structure.

How Format is Applied

From PromoStandards.ts:147-151, the format is checked before returning the response:
axios
  .post(endpoint.url, requestXML, {
    headers: {
      'Content-Type': 'text/xml',
      SOAPAction: method,
    },
  })
  .then((result: any) => {
    this.format === 'json'
      ? resolve(Utils.convertXMLtoJSON(result.data))  // Convert to JSON
      : resolve(result.data);                         // Return raw XML
  })
  .catch((error: Error) => reject(error));
1

SOAP Request

SDK sends XML request to supplier endpoint
2

XML Response

Supplier returns XML response (SOAP envelope)
3

Format Check

SDK checks the format setting (json or xml)
4

Conversion

If json, converts using convertXMLtoJSON(), otherwise returns raw XML
5

Promise Resolution

Returns formatted response to your application

Handling Arrays in JSON Responses

PromoStandards responses contain many arrays (colors, sizes, pricing, etc.). The SDK handles these intelligently:

Safe Array Access

// Always check if array exists and has items
const colors = result?.Envelope?.Body?.getProductResponse?.Product?.ColorArray;

if (colors && Array.isArray(colors)) {
  colors.forEach(color => {
    console.log(color.colorName);
  });
} else if (colors) {
  // Single item, not an array
  console.log(colors.colorName);
}

Using ensureArray Helper

The SDK’s internal ensureArray utility (Utils.ts:4) can be useful:
const ensureArray = (obj) => obj instanceof Array ? obj : [obj];

// Now you can safely iterate
const colors = ensureArray(
  result?.Envelope?.Body?.getProductResponse?.Product?.ColorArray
);

colors.forEach(color => {
  console.log(color.colorName);
});

Response Format Best Practices

Use JSON by Default

JSON is easier to work with in JavaScript and is the recommended format for most applications.

Handle Missing Data

Always use optional chaining (?.) when accessing nested response properties.

Validate Arrays

Check if array fields are actually arrays before iterating, or use ensureArray.

Log Raw Responses

During debugging, temporarily switch to XML format to see raw SOAP responses.

Debugging with XML Format

When troubleshooting API issues, XML format helps you see the raw SOAP response:
// Temporarily use XML format for debugging
const debugClient = new PromoStandards.Client({
  id: 'username',
  password: 'password',
  endpoints: [/* ... */],
  format: 'xml'
});

const xmlResponse = await debugClient.productData.getProduct(params);
console.log('Raw SOAP Response:', xmlResponse);

// Check for SOAP faults or unexpected structure
if (xmlResponse.includes('soap:Fault')) {
  console.error('SOAP Fault detected!');
}

Switching Formats Dynamically

The format is set during client initialization, but you can create multiple clients:
const baseConfig = {
  id: process.env.SUPPLIER_USERNAME,
  password: process.env.SUPPLIER_PASSWORD,
  endpoints: [/* ... */]
};

const jsonClient = new PromoStandards.Client({
  ...baseConfig,
  format: 'json'
});

const xmlClient = new PromoStandards.Client({
  ...baseConfig,
  format: 'xml'
});

// Use based on need
const jsonData = await jsonClient.productData.getProduct(params);
const xmlData = await xmlClient.productData.getProduct(params);

Next Steps

Client Configuration

Learn about configuring the PromoStandards Client

Error Handling

Handle errors in API responses

Build docs developers (and LLMs) love