Skip to content

adding swatStatistics file to make statistics.json call to apps.bazaarvoice.com and fix for PD-243471 #141

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions lib/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,63 @@ getStatistics({

---

---

### swatGetStatistics

Returns the statistics for a given list of products. API call can be made to apps.bazaarvoice.com or api.bazaarvoice.com

#### Syntax

```javascript
api.get('swatStatistics', options)

// or
const getStatistics = require('bv-ui-core/lib/api/swatStatistics')
swatGetStatistics(options)
```

#### Parameters

##### options

An object with key/value pairs of inputs. Most values are required.

##### options.productIds

An array of product ids to query for. A warning will be emitted if over 100 products are requested.

##### options.useBackend
A boolean value. If set to true, the call will be made to apps.bazaarvoice.com. If set to false, the call will be made to api.bazaarvoice.com.

##### options.environment

A string representing the data environment. Accepts `qa`, `staging` or
`production`.

##### options.key

Your api key.

##### options.type

A string representing the type of statistics you want to query for. Currently
accepts `Reviews` or `NativeReviews`.

Using `Reviews` returns statistics for all content, including syndicated
content (if enabled on your API key). If you only want statistics for reviews
you own that were written for the products specified, use `NativeReviews`
instead.

##### options.filters (optional)

An object representing filters keyed by the name of the filter. `ContentLocale `
can be provided to specify a locale subset for the statistics. If no
`ContentLocale` is provided, will return the global statistics for each product
in the query.



----

[0]: https://developer.bazaarvoice.com/docs/read/conversations
157 changes: 157 additions & 0 deletions lib/api/swatStatistics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/* global fetch */
/**
* @fileOverview Module for interacting with the statistcs.json endpoint from both api.bazaarvoice.com and apps.bazaarvoice.com
*
*/
const envPrefixMap = {
qa: 'qa.',
staging: 'stg.',
production: '.'
};

// Default configuration
const API_VERSION = 5.4;
const MAX_REQUESTED_IDS = 100;

/**
* Calls the statistics.json API with provided options. Returns a promise that
* is fulfilled with an array of Results from the API or rejected with the error
* message.
*
* Example:
*
* getStatistics({
* productIds: ['product1', 'product2', 'product3'],
* environment: 'qa',
* key: 'clients_api_key',
* type: 'Reviews',
* filters: {
* ContentLocale: 'en_US'
* }
* }).then(results => {
* // Do something with results
* }, errorMsg => {
* // Do something with error.
* })
*
* https://developer.bazaarvoice.com/docs/read/conversations/statistics/display/5_4
*
* @param {Object} options object that contains options
* @param {Array} options.productIds - array of product IDs
* @param {Array} options.environment - the data environment
* @param {Array} options.key - client's api key
* @param {string} options.type - Using "Reviews" returns statistics for all
* content, including syndicated content (if enabled on your API key).
* If you only want statistics for reviews you own that were written for
* the products specified, use "NativeReviews" instead.
* @param {Object} [options.filters] - Filters object. Keyed by filter name.
* @return {Promise} a promise that will be resolved with the raw results
* from the statistics call.
*/
function swatGetStatistics ({
productIds,
useBackend,
environment,
key,
type,
incentivized = false,
filters = {}
}) {
if (!productIds || !Array.isArray(productIds)) {
throw new TypeError('productIds must be an array');
}

const envPrefix = envPrefixMap[environment];
if (!envPrefix) {
throw new TypeError('environment must be "qa", "staging", or "production"');
}

if (!key) {
throw new TypeError('key must be provided');
}

if (!type || !(type === 'Reviews' || type === 'NativeReviews')) {
throw new TypeError('type must be "Reviews" or "NativeReviews"');
}
let basePath = ''
if (useBackend) {
basePath = `https://apps-${envPrefix}bazaarvoice.com/api/data/statistics.json`
}
else {
basePath = `https://${envPrefix}api.bazaarvoice.com/data`
}


let uri =
`${basePath}` +
`?apiversion=${API_VERSION}` +
`&passkey=${key}` +
`&stats=${type}` +
Object.keys(filters)
.map(filter => `&filter=${filter}:${filters[filter]}`)
.join();

// We should add `incentivizedStats` request param in case
// if `incentivized` flag is enabled that means such reviews
// have to be loaded in response
if (incentivized) {
uri = uri + `&incentivizedStats=${incentivized}`;
}

// Clone the productIds so we can manipulate it.
productIds = [...productIds];
const productIdChunks = [];

if (productIds.length > 100) {
console.warn('Requesting more than 100 products is not recommended!');
}

while (productIds.length > 0) {
productIdChunks.push(productIds.splice(0, MAX_REQUESTED_IDS));
}

return Promise.all(
productIdChunks.map(
products =>
new Promise((resolve, reject) => {
const requestUri = `${uri}&filter=ProductId:${products.join(',')}`;
return fetch(requestUri)
.then(response => response.json())
.then(json => {
// If there are errors in the actual response body (from API)
// we need to handle them here.
if (json.HasErrors) {
let errors = json.Errors;
// If for some reason errors is empty or doesn't exist,
if (!errors || !Array.isArray(errors) || errors.length <= 0) {
reject({
Message: 'An unknown error occurred.',
Code: 'ERROR_UNKNOWN',
});
}
else {
// We can reasonably assume that if an error occurred for this
// request it should only have a single error response
// unlike submission api errors, which have multiples.
reject(json.Errors[0]);
}
}
else {
resolve(json.Results);
}
});
})
)
).then(results => {
if (results.length === 0) {
return results;
}
else {
return results.reduce((a, b) => {
return a.concat(b);
});
}
});
}

module.exports = swatGetStatistics;
5 changes: 4 additions & 1 deletion lib/bvFetch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ module.exports = function BvFetch ({ shouldCache, cacheName, cacheLimit }) {
.then((cache) => {
return cache.match(cacheKey)
.then((cachedResponse) => {

if (!cachedResponse) {
this.cachedUrls.delete(cacheKey)
return Promise.resolve(null);
}
const cachedTime = cachedResponse.headers.get('X-Bazaarvoice-Cached-Time');
const ttl = cachedResponse.headers.get('Cache-Control').match(/max-age=(\d+)/)[1];
const currentTimestamp = Date.now();
Expand Down