/* * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Copyright (c) 2020 Mobify Research & Development Inc. All rights reserved. */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Shop API
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* OpenAPI spec version: 20.4
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*
*/
import superagent from 'superagent'
import querystring from 'querystring'
import Fault from './models/Fault'
/**
* @module ApiClient
* @version 20.4
*/
const defaultConfig = {
basePath: 'https://localhost/s/siteId/dw/shop/v20_4',
cache: true,
defaultHeaders: {},
enableCookies: false,
overrideHttpPut: true,
timeout: 60000,
}
/**
* Manages low level client-server communications, parameter marshalling, etc. There should not be any need for an
* application to use this class directly - the *Api and model classes provide the public API for the service. The
* contents of this file should be regarded as internal but are documented for completeness.
* @alias module:ApiClient
* @class
*/
export default class ApiClient {
constructor(config = defaultConfig) {
const {
basePath,
defaultHeaders,
timeout,
cache,
enableCookies,
clientUsername,
clientPassword,
oauth2AccessToken,
overrideHttpPut
} = Object.assign(defaultConfig, config)
// verify the required parameter 'basepath' is set
if (basePath === undefined || basePath === null || basePath === '') {
throw new Error('Missing the required parameter \'basePath\' when calling constructing ApiClient')
}
/**
* The base URL against which to resolve every API call's (relative) path.
* @type {String}
* @default https://localhost/s/siteId/dw/shop/v20_4
*/
this.basePath = basePath.replace(/\/+$/, '')
/**
* The authentication methods to be included for all API calls.
* @type {Array.<String>}
*/
this.authentications = {
client_id: {
type: 'apiKey',
in: 'header',
name: 'x-dw-client-id'
},
customers_auth: {
type: 'basic'
},
oauth2_application: {
type: 'oauth2'
}
}
if (oauth2AccessToken) {
const oauth2_application = this.authentications.oauth2_application
oauth2_application.accessToken = oauth2AccessToken
}
if (clientUsername && clientPassword) {
const customers_auth = this.authentications.customers_auth
customers_auth.username = clientUsername
customers_auth.password = clientPassword
}
/**
* If set to true, endpoints that normally use HTTP `PUT` will
* be sent using `POST` with an aditional header (x-dw-http-method-override: `PUT`).
* Please refer to the following Salesforce documentation {@link https://documentation.demandware.com/DOC1/topic/com.demandware.dochelp/OCAPI/18.8/usage/HttpMethods.html}
* for more information.
* @type {Boolean}
* @default true
*/
this.overrideHttpPut = overrideHttpPut
/**
* The default HTTP headers to be included for all API calls.
* @type {Array.<String>}
* @default {}
*/
this.defaultHeaders = defaultHeaders
/**
* The default HTTP timeout for all API calls.
* @type {Number}
* @default 60000
*/
this.timeout = timeout
/**
* If set to false an additional timestamp parameter is added to all API GET calls to
* prevent browser caching
* @type {Boolean}
* @default true
*/
this.cache = cache
/**
* If set to true, the client will save the cookies from each server
* response, and return them in the next request.
* @default false
*/
this.enableCookies = enableCookies
/*
* Used to save and return cookies in a node.js (non-browser) setting,
* if this.enableCookies is set to true.
*/
if (typeof window === 'undefined') {
this.agent = new superagent.agent()
}
}
/**
* Returns a string representation for an actual parameter.
* @param param The actual parameter.
* @returns {String} The string representation of <code>param</code>.
*/
paramToString(param) {
if (param === undefined || param === null) {
return ''
}
if (param instanceof Date) {
return param.toJSON()
}
return param.toString()
}
/**
* Returns a encoded string representation for an actual parameter.
* @param param The actual parameter.
* @returns {String} The string representation of <code>param</code>.
*/
paramToEncodedString(param) {
let value = ''
if (param === undefined || param === null) {
return value
}
if (param instanceof Date) {
value = encodeURIComponent(param.toJSON())
} else if (param instanceof Array) {
value = param.map((value) => encodeURIComponent(value)).join(',')
} else {
value = encodeURIComponent(param.toString())
}
return value
}
/**
* Builds full URL by appending the given path to the base URL and replacing path parameter place-holders with parameter values.
* NOTE: query parameters are not handled here.
* @param {String} path The path to append to the base URL.
* @param {Object} pathParams The parameter values to append.
* @returns {String} The encoded path with parameter values substituted.
*/
buildUrl(path, pathParams) {
if (!path.match(/^\//)) {
path = `/${path}`
}
let url = this.basePath + path
url = url.replace(/\{([\w-]+)\}/g, (fullMatch, key) => {
let value
if (pathParams.hasOwnProperty(key)) {
value = this.paramToEncodedString(pathParams[key])
} else {
value = encodeURIComponent(fullMatch)
}
return value
})
return url
}
/**
* Checks whether the given content type represents JSON.<br>
* JSON content type examples:<br>
* <ul>
* <li>application/json</li>
* <li>application/json; charset=UTF8</li>
* <li>APPLICATION/JSON</li>
* </ul>
* @param {String} contentType The MIME content type to check.
* @returns {Boolean} <code>true</code> if <code>contentType</code> represents JSON, otherwise <code>false</code>.
*/
isJsonMime(contentType) {
return Boolean(contentType !== null && contentType.match(/^application\/json(;.*)?$/i))
}
/**
* Chooses a content type from the given array, with JSON preferred; i.e. return JSON if included, otherwise return the first.
* @param {Array.<String>} contentTypes
* @returns {String} The chosen content type, preferring JSON.
*/
jsonPreferredMime(contentTypes) {
for (let i = 0; i < contentTypes.length; i++) {
if (this.isJsonMime(contentTypes[i])) {
return contentTypes[i]
}
}
return contentTypes[0]
}
/**
* Checks whether the given parameter value represents file-like content.
* @param param The parameter to check.
* @returns {Boolean} <code>true</code> if <code>param</code> represents a file.
*/
isFileParam(param) {
// fs.ReadStream in Node.js and Electron (but not in runtime like browserify)
if (typeof require === 'function') {
let fs
try {
fs = require('fs')
} catch (err) {}
if (fs && fs.ReadStream && param instanceof fs.ReadStream) {
return true
}
}
// Buffer in Node.js
if (typeof Buffer === 'function' && param instanceof Buffer) { // eslint-disable-line no-undef
return true
}
// Blob in browser
if (typeof Blob === 'function' && param instanceof Blob) {
return true
}
// File in browser (it seems File object is also instance of Blob, but keep this for safe)
if (typeof File === 'function' && param instanceof File) {
return true
}
return false
}
/**
* Normalizes parameter values:
* <ul>
* <li>remove nils</li>
* <li>keep files and arrays</li>
* <li>format to string with `paramToString` for other cases</li>
* </ul>
* @param {Object.<String, Object>} params The parameters as object properties.
* @returns {Object.<String, Object>} normalized parameters.
*/
normalizeParams(params) {
const newParams = {}
for (const key in params) {
if (params.hasOwnProperty(key) && params[key] !== undefined && params[key] !== null) {
const value = params[key]
if (this.isFileParam(value) || Array.isArray(value)) {
newParams[key] = value
} else {
newParams[key] = this.paramToString(value)
}
}
}
return newParams
}
/**
* Builds an object with refinement keys 1..n given a an array of refinements.
* A numbered suffix will not be applied if the number of refinements is equal to 1.
* @param {Array} refinements Array of refinement strings
* @returns {Object} An object with refinement keys numbered 1 ... n with their
* string representation value.
*/
buildRefineParams(refinements) {
refinements = refinements || []
return refinements.length
? refinements.reduce(
(acc, curr, idx, arr) => {
Object.assign(acc, {[arr.length > 1 ? `refine_${idx + 1}` : 'refine']: this.paramToString(curr)})
return acc
},
{} // Reduce array to populate a new object with formatted key/values.
)
: {}
}
/**
* Builds a string representation of an array-type actual parameter, according to the given collection format.
* @param {Array} param An array parameter.
* @param {module:ApiClient.CollectionFormatEnum} collectionFormat The array element separator strategy.
* @returns {String|Array} A string representation of the supplied collection, using the specified delimiter. Returns
* <code>param</code> as is if <code>collectionFormat</code> is <code>multi</code>.
*/
buildCollectionParam(param, collectionFormat) {
if (param === null || param === undefined) {
return null
}
switch (collectionFormat) {
case 'csv':
return param.map(this.paramToString).join(',')
case 'ssv':
return param.map(this.paramToString).join(' ')
case 'tsv':
return param.map(this.paramToString).join('\t')
case 'pipes':
return param.map(this.paramToString).join('|')
case 'multi':
// return the array directly as SuperAgent will handle it as expected
return param.map(this.paramToString)
default:
throw new Error(`Unknown collection format: ${collectionFormat}`)
}
}
/**
* Applies authentication headers to the request.
* @param {Object} request The request object created by a <code>superagent()</code> call.
* @param {Array.<String>} authNames An array of authentication method names.
*/
applyAuthToRequest(request, authNames) {
authNames.forEach((authName) => {
const auth = this.authentications[authName]
switch (auth.type) {
case 'basic':
if (auth.username || auth.password) {
request.auth(auth.username || '', auth.password || '')
}
break
case 'apiKey':
if (auth.apiKey) {
const data = {}
if (auth.apiKeyPrefix) {
data[auth.name] = `${auth.apiKeyPrefix} ${auth.apiKey}`
} else {
data[auth.name] = auth.apiKey
}
if (auth.in === 'header') {
request.set(data)
} else {
request.query(data)
}
}
break
case 'oauth2':
if (auth.accessToken) {
request.set({
Authorization: `Bearer ${auth.accessToken}`
})
}
break
default:
throw new Error(`Unknown authentication type: ${auth.type}`)
}
})
}
/**
* Deserializes an HTTP response body into a value of the specified type.
* @param {Object} response A SuperAgent response object.
* @param {(String|Array.<String>|Object.<String, Object>|Function)} returnType The type to return. Pass a string for simple types
* or the constructor function for a complex type. Pass an array containing the type name to return an array of that type. To
* return an object, pass an object with one property whose name is the key type and whose value is the corresponding value type:
* all properties on <code>data<code> will be converted to this type.
* @returns A value of the specified type.
*/
deserialize(response, returnType) {
if (response === null || returnType === null || response.status === 204) {
return null
}
// Rely on SuperAgent for parsing response body.
// See http://visionmedia.github.io/superagent/#parsing-response-bodies
let data = response.body
if (data === null || (typeof data === 'object' && typeof data.length === 'undefined' && !Object.keys(data).length)) {
// SuperAgent does not always produce a body; use the unparsed response as a fallback
data = response.text
}
return ApiClient.convertToType(data, returnType)
}
/**
* Invokes the REST service using the supplied settings and parameters.
* @param {String} path The base URL to invoke.
* @param {String} httpMethod The HTTP method to use.
* @param {Object.<String, String>} pathParams A map of path parameters and their values.
* @param {Object.<String, Object>} queryParams A map of query parameters and their values.
* @param {Object.<String, Object>} headerParams A map of header parameters and their values.
* @param {Object.<String, Object>} formParams A map of form parameters and their values.
* @param {Object} bodyParam The value to pass as the request body.
* @param {Array.<String>} authNames An array of authentication type names.
* @param {Array.<String>} contentTypes An array of request MIME types.
* @param {Array.<String>} accepts An array of acceptable response MIME types.
* @param {(String|Array|ObjectFunction)} returnType The required type to return; can be a string for simple types or the
* constructor for a complex type.
* @returns {Promise} A {@link https://www.promisejs.org/|Promise} object.
*/
callApi(path, httpMethod, pathParams,
queryParams, headerParams, formParams, bodyParam, authNames, contentTypes, accepts,
returnType) {
// emulate PUT method because they are not allowed on staging and production environments
if (this.overrideHttpPut && httpMethod.toUpperCase() === 'PUT') {
httpMethod = 'POST'
headerParams = Object.assign(headerParams || {}, {'x-dw-http-method-override': 'PUT'})
}
const url = this.buildUrl(path, pathParams)
const request = superagent(httpMethod, url)
// apply authentications
this.applyAuthToRequest(request, authNames)
// set query parameters
if (httpMethod.toUpperCase() === 'GET' && this.cache === false) {
queryParams._ = new Date().getTime()
}
request.query(this.normalizeParams(queryParams))
// set header parameters
request.set(this.defaultHeaders).set(this.normalizeParams(headerParams))
// set request timeout
request.timeout(this.timeout)
const contentType = this.jsonPreferredMime(contentTypes)
if (contentType) {
// Issue with superagent and multipart/form-data (https://github.com/visionmedia/superagent/issues/746)
if (contentType !== 'multipart/form-data') {
request.type(contentType)
}
} else if (!request.header['Content-Type']) {
request.type('application/json')
}
if (contentType === 'application/x-www-form-urlencoded') {
request.send(querystring.stringify(this.normalizeParams(formParams)))
} else if (contentType === 'multipart/form-data') {
const _formParams = this.normalizeParams(formParams)
for (const key in _formParams) {
if (_formParams.hasOwnProperty(key)) {
if (this.isFileParam(_formParams[key])) {
// file field
request.attach(key, _formParams[key])
} else {
request.field(key, _formParams[key])
}
}
}
} else if (bodyParam) {
request.send(bodyParam)
}
const accept = this.jsonPreferredMime(accepts)
if (accept) {
request.accept(accept)
}
if (returnType === 'Blob') {
request.responseType('blob')
} else if (returnType === 'String') {
request.responseType('string')
}
// Attach previously saved cookies, if enabled
if (this.enableCookies) {
if (typeof window === 'undefined') {
this.agent._attachCookies(request)
} else {
request.withCredentials()
}
}
return this.sendApiRequest(request, returnType)
}
/**
* Sends the generated superagent request and deserializes the response.
* @param {module:superagent.Request} request The superagent request to send.
* @param {String} returnType The type to deserialize the response into.
* @returns {Promise} A {@link https://www.promisejs.org/|Promise} object.
*/
sendApiRequest(request, returnType) {
return new Promise((resolve, reject) => {
request.end((error, response) => {
if (error) {
// Looks like there was an fault returned from the API
const hasErrorMessage = error.response && error.response.text
if (hasErrorMessage) {
try {
const fault = Fault.constructFromObject(JSON.parse(error.response.text).fault)
reject(fault)
} catch (err) {
// Reject immediately on parsing error.
reject(err)
}
}
// Most likely a network error has happened here so include entire error.
reject(error)
} else {
try {
const data = this.deserialize(response, returnType)
if (this.enableCookies && typeof window === 'undefined') {
this.agent._saveCookies(response)
}
resolve({
data,
response
})
} catch (err) {
reject(err)
}
}
})
})
}
/**
* Parses an ISO-8601 string representation of a date value.
* @param {String} str The date value as a string.
* @returns {Date} The parsed date object.
*/
static parseDate(str) {
return new Date(str.replace(/T/i, ' '))
}
/**
* Converts a value to the specified type.
* @param {(String|Object)} data The data to convert, as a string or object.
* @param {(String|Array.<String>|Object.<String, Object>|Function)} type The type to return. Pass a string for simple types
* or the constructor function for a complex type. Pass an array containing the type name to return an array of that type. To
* return an object, pass an object with one property whose name is the key type and whose value is the corresponding value type:
* all properties on <code>data<code> will be converted to this type.
* @returns An instance of the specified type or null or undefined if data is null or undefined.
*/
static convertToType(data, type) {
if (data === null || data === undefined) {
return data
}
switch (type) {
case 'Boolean':
return Boolean(data)
case 'Integer':
return parseInt(data, 10)
case 'Number':
return parseFloat(data)
case 'String':
return String(data)
case 'Date':
return ApiClient.parseDate(String(data))
case 'Blob':
return data
default:
if (type === Object) {
// generic object, return directly
return data
} else if (typeof type === 'function') {
// for model type like: User
const model = type.constructFromObject(data)
// add support for custom properties
// NOTE: We'll have to expand on this further as this only suports
// simple typed values
for (const k in data) {
if (data.hasOwnProperty(k) && /^c_/.test(k)) {
model[k] = data[k]
}
}
return model
} else if (Array.isArray(type)) {
// for array type like: ['String']
const itemType = type[0]
return data.map((item) => {
return ApiClient.convertToType(item, itemType)
})
} else if (typeof type === 'object') {
// for plain object type like: {'String': 'Integer'}
let keyType
let valueType
for (const k in type) {
if (type.hasOwnProperty(k)) {
keyType = k
valueType = type[k]
break
}
}
const result = {}
for (const k in data) {
if (data.hasOwnProperty(k)) {
const key = ApiClient.convertToType(k, keyType)
const value = ApiClient.convertToType(data[k], valueType)
result[key] = value
}
}
return result
} else {
// for unknown type, return the data directly
return data
}
}
}
/**
* Constructs a new map or array model from REST data.
* @param data {Object|Array} The REST data.
* @param obj {Object|Array} The target object or array.
*/
static constructFromObject(data, obj, itemType) {
if (Array.isArray(data)) {
for (let i = 0; i < data.length; i++) {
if (data.hasOwnProperty(i)) {
obj[i] = ApiClient.convertToType(data[i], itemType)
}
}
} else {
for (const k in data) {
if (data.hasOwnProperty(k)) {
obj[k] = ApiClient.convertToType(data[k], itemType)
}
}
}
}
}
/**
* Enumeration of collection format separator strategies.
* @enum {String}
* @readonly
*/
ApiClient.CollectionFormatEnum = {
/**
* Comma-separated values. Value: <code>csv</code>
* @const
*/
CSV: ',',
/**
* Space-separated values. Value: <code>ssv</code>
* @const
*/
SSV: ' ',
/**
* Tab-separated values. Value: <code>tsv</code>
* @const
*/
TSV: '\t',
/**
* Pipe(|)-separated values. Value: <code>pipes</code>
* @const
*/
PIPES: '|',
/**
* Native array. Value: <code>multi</code>
* @const
*/
MULTI: 'multi'
}
/**
* The default API client implementation.
* @type {module:ApiClient}
*/
ApiClient.instance = new ApiClient(defaultConfig)