Skip to content

Commit

Permalink
Support setting the region of your DB. Added Update / Delete More Ite…
Browse files Browse the repository at this point in the history
…ms endpoints.

Use got as the HTTP library instead of the deprecated request library.

Breaking changes:
ApiClient constructor: Removed alwaysUseHttps parameter. Use options.protocol instead.
Removed deprecated endpoints Item Based Recommendation and User Based Recommendation
  • Loading branch information
OndraFiedler committed Apr 20, 2022
1 parent c582fbd commit c76b06d
Show file tree
Hide file tree
Showing 55 changed files with 741 additions and 878 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ client.send(new AddDetailView,
var recombee = require('recombee-api-client');
var rqs = recombee.requests;

var client = new recombee.ApiClient('--my-database-id--', '--db-private-token--');
var client = new recombee.ApiClient('--my-database-id--', '--db-private-token--', {region: 'us-west'});

// Prepare some userIDs and itemIDs
const NUM = 100;
Expand Down Expand Up @@ -96,7 +96,7 @@ client.send(new rqs.Batch(purchases))
var recombee = require('recombee-api-client');
var rqs = recombee.requests;

var client = new recombee.ApiClient('--my-database-id--', '--db-private-token--');
var client = new recombee.ApiClient('--my-database-id--', '--db-private-token--', {region: 'ap-se'});
const NUM = 100;

// We will use computers as items in this example
Expand Down
86 changes: 49 additions & 37 deletions lib/api-client.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
'use strict';

const jsSHA = require("jssha");
const rp = require('request-promise');
const rp_errors = require('request-promise/errors');
const got = require('got');

const api_errors = require('./errors');
const requests = require('./requests');
Expand All @@ -17,15 +16,17 @@ class ApiClient {
* Construct the client
* @param {string} databaseId - ID of your database
* @param {string} secretToken - Corresponding secret token
* @param {boolean} alwaysUseHttps - If true, all requests are sent using HTTPS (default: true)
* @param {Object} options - Other custom options
*/
constructor (databaseId, token, alwaysUseHttps, options) {
constructor (databaseId, token, options) {
this.databaseId = databaseId;
this.token = token;
this.alwaysUseHttps = (alwaysUseHttps === undefined) ? true : alwaysUseHttps;
this.options = options || {};
this.baseUri = process.env.RAPI_URI || this.options.baseUri || 'rapi.recombee.com';

if (Object.getPrototypeOf(this.options) !== Object.prototype) throw new Error(`options must be given as an Object (${this.options} given instead)`);

this.protocol = this.options.protocol || 'https';
this.baseUri = this._getBaseUri()
}

/**
Expand All @@ -41,50 +42,69 @@ class ApiClient {
let url = this._buildRequestUrl(request);
let options = {
method: request.method,
uri: url,
url: url,
headers: {'Accept': 'application/json',
'Content-Type': 'application/json',
'User-Agent': 'recombee-node-api-client/3.2.0'},
timeout: request.timeout,
resolveWithFullResponse: true,
json: true
'User-Agent': 'recombee-node-api-client/4.0.0'},
timeout: request.timeout
};

if (this.options.proxy)
options.proxy = this.options.proxy;

if (request.bodyParameters())
options.body = request.bodyParameters();
if (Object.entries(request.bodyParameters()).length > 0)
options.json = request.bodyParameters();

return rp(options)
.then(this._parseResponse)
return got(options)
.json()
.then((response)=> {
return new Promise( (resolve) => {
if (callback) { return callback(null, response); }
return resolve(response);
});
})
.catch(rp_errors.StatusCodeError,((error) => {
throw new api_errors.ResponseError(request, error.statusCode, error.message);
.catch((error) => {
if (error instanceof got.HTTPError) {
error = new api_errors.ResponseError(request, error.response.statusCode, error.response.body);
}
))
.catch(rp_errors.RequestError,((error) => {
if(error.cause.code === 'ETIMEDOUT' || error.cause.code === 'ESOCKETTIMEDOUT')
throw new api_errors.TimeoutError(request, error);
throw error;
else if (error instanceof got.RequestError) {
if(error.code === 'ETIMEDOUT' || error.code === 'ESOCKETTIMEDOUT') {
error = new api_errors.TimeoutError(request, error);
}
}
))
.catch((error) => {
if (callback) {return callback(error)};
throw error;
});
}

_getRegionalBaseUri(region) {
const uri = {
'ap-se': 'rapi-ap-se.recombee.com',
'ca-east': 'rapi-ca-east.recombee.com',
'eu-west': 'rapi-eu-west.recombee.com',
'us-west': 'rapi-us-west.recombee.com'
}[region.toLowerCase()];

if (uri === undefined) {
throw new Error(`Region "${region}" is unknown. You may need to update the version of the SDK.`)
}

return uri;
}

_getBaseUri() {
let baseUri = process.env.RAPI_URI || this.options.baseUri;
if (this.options.region) {
if (baseUri) {
throw new Error('baseUri and region cannot be specified at the same time');
}
baseUri = this._getRegionalBaseUri(this.options.region);
}
return baseUri || 'rapi.recombee.com';
}

_buildRequestUrl(request) {
let protocol = (request.ensureHttps || this.alwaysUseHttps) ? 'https' : 'http';
let usedProtocol = (request.ensureHttps) ? 'https' : this.protocol;
let reqUrl = request.path + this._encodeRequestQueryParams(request);
let signedUrl = this._signUrl(reqUrl);
return protocol + '://' + this.baseUri + signedUrl;
return usedProtocol + '://' + this.baseUri + signedUrl;
}

_encodeRequestQueryParams(request) {
Expand Down Expand Up @@ -161,14 +181,6 @@ class ApiClient {
});
}

_parseResponse(response) {
return new Promise(
function (resolve, reject) {
resolve(response.body);
}
);
}

_signUrl (req_part) {
let url = '/' + this.databaseId + req_part;
url += (req_part.indexOf("?") == -1 ? "?" : "&" ) + "hmac_timestamp=" + parseInt(new Date().getTime() / 1000);
Expand Down
2 changes: 1 addition & 1 deletion lib/requests/delete-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const rqs = require("./request");
/**
* Deletes an item of given `itemId` from the catalog.
* If there are any *purchases*, *ratings*, *bookmarks*, *cart additions* or *detail views* of the item present in the database, they will be deleted in cascade as well. Also, if the item is present in some *series*, it will be removed from all the *series* where present.
* If an item becomes obsolete/no longer available, it is often meaningful to keep it in the catalog (along with all the interaction data, which are very useful), and only exclude the item from recommendations. In such a case, use [ReQL filter](https://docs.recombee.com/reql.html) instead of deleting the item completely.
* If an item becomes obsolete/no longer available, it is meaningful to keep it in the catalog (along with all the interaction data, which are very useful), and **only exclude the item from recommendations**. In such a case, use [ReQL filter](https://docs.recombee.com/reql.html) instead of deleting the item completely.
*/
class DeleteItem extends rqs.Request {

Expand Down
44 changes: 44 additions & 0 deletions lib/requests/delete-more-items.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
This file is auto-generated, do not edit
*/

'use strict';
const rqs = require("./request");

/**
* Delete all the items that pass the filter.
* If an item becomes obsolete/no longer available, it is meaningful to **keep it in the catalog** (along with all the interaction data, which are very useful), and **only exclude the item from recommendations**. In such a case, use [ReQL filter](https://docs.recombee.com/reql.html) instead of deleting the item completely.
*/
class DeleteMoreItems extends rqs.Request {

/**
* Construct the request
* @param {string} filter - A [ReQL](https://docs.recombee.com/reql.html) expression, which return `true` for the items that shall be updated.
*/
constructor(filter) {
super('DELETE', '/more-items/', 1000, false);
this.filter = filter;
}

/**
* Get body parameters
* @return {Object} The values of body parameters (name of parameter: value of the parameter)
*/
bodyParameters() {
let params = {};
params.filter = this.filter;

return params;
}

/**
* Get query parameters
* @return {Object} The values of query parameters (name of parameter: value of the parameter)
*/
queryParameters() {
let params = {};
return params;
}
}

exports.DeleteMoreItems = DeleteMoreItems
2 changes: 1 addition & 1 deletion lib/requests/delete-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class DeleteUser extends rqs.Request {

/**
* Construct the request
* @param {string} userId - ID of the user to be added.
* @param {string} userId - ID of the user to be deleted.
*/
constructor(userId) {
super('DELETE', `/users/${userId}`, 1000, false);
Expand Down
4 changes: 2 additions & 2 deletions lib/requests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ exports.AddItemProperty = require("./add-item-property").AddItemProperty;
exports.DeleteItemProperty = require("./delete-item-property").DeleteItemProperty;
exports.GetItemPropertyInfo = require("./get-item-property-info").GetItemPropertyInfo;
exports.ListItemProperties = require("./list-item-properties").ListItemProperties;
exports.UpdateMoreItems = require("./update-more-items").UpdateMoreItems;
exports.DeleteMoreItems = require("./delete-more-items").DeleteMoreItems;
exports.AddSeries = require("./add-series").AddSeries;
exports.DeleteSeries = require("./delete-series").DeleteSeries;
exports.ListSeries = require("./list-series").ListSeries;
Expand Down Expand Up @@ -63,8 +65,6 @@ exports.RecommendItemsToItem = require("./recommend-items-to-item").RecommendIte
exports.RecommendNextItems = require("./recommend-next-items").RecommendNextItems;
exports.RecommendUsersToUser = require("./recommend-users-to-user").RecommendUsersToUser;
exports.RecommendUsersToItem = require("./recommend-users-to-item").RecommendUsersToItem;
exports.UserBasedRecommendation = require("./user-based-recommendation").UserBasedRecommendation;
exports.ItemBasedRecommendation = require("./item-based-recommendation").ItemBasedRecommendation;
exports.SearchItems = require("./search-items").SearchItems;
exports.AddSearchSynonym = require("./add-search-synonym").AddSearchSynonym;
exports.ListSearchSynonyms = require("./list-search-synonyms").ListSearchSynonyms;
Expand Down
Loading

0 comments on commit c76b06d

Please sign in to comment.