Skip to content

Commit c76b06d

Browse files
committed
Support setting the region of your DB. Added Update / Delete More Items 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
1 parent c582fbd commit c76b06d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+741
-878
lines changed

Diff for: README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ client.send(new AddDetailView,
4444
var recombee = require('recombee-api-client');
4545
var rqs = recombee.requests;
4646

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

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

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

102102
// We will use computers as items in this example

Diff for: lib/api-client.js

+49-37
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
'use strict';
22

33
const jsSHA = require("jssha");
4-
const rp = require('request-promise');
5-
const rp_errors = require('request-promise/errors');
4+
const got = require('got');
65

76
const api_errors = require('./errors');
87
const requests = require('./requests');
@@ -17,15 +16,17 @@ class ApiClient {
1716
* Construct the client
1817
* @param {string} databaseId - ID of your database
1918
* @param {string} secretToken - Corresponding secret token
20-
* @param {boolean} alwaysUseHttps - If true, all requests are sent using HTTPS (default: true)
2119
* @param {Object} options - Other custom options
2220
*/
23-
constructor (databaseId, token, alwaysUseHttps, options) {
21+
constructor (databaseId, token, options) {
2422
this.databaseId = databaseId;
2523
this.token = token;
26-
this.alwaysUseHttps = (alwaysUseHttps === undefined) ? true : alwaysUseHttps;
2724
this.options = options || {};
28-
this.baseUri = process.env.RAPI_URI || this.options.baseUri || 'rapi.recombee.com';
25+
26+
if (Object.getPrototypeOf(this.options) !== Object.prototype) throw new Error(`options must be given as an Object (${this.options} given instead)`);
27+
28+
this.protocol = this.options.protocol || 'https';
29+
this.baseUri = this._getBaseUri()
2930
}
3031

3132
/**
@@ -41,50 +42,69 @@ class ApiClient {
4142
let url = this._buildRequestUrl(request);
4243
let options = {
4344
method: request.method,
44-
uri: url,
45+
url: url,
4546
headers: {'Accept': 'application/json',
4647
'Content-Type': 'application/json',
47-
'User-Agent': 'recombee-node-api-client/3.2.0'},
48-
timeout: request.timeout,
49-
resolveWithFullResponse: true,
50-
json: true
48+
'User-Agent': 'recombee-node-api-client/4.0.0'},
49+
timeout: request.timeout
5150
};
5251

53-
if (this.options.proxy)
54-
options.proxy = this.options.proxy;
55-
56-
if (request.bodyParameters())
57-
options.body = request.bodyParameters();
52+
if (Object.entries(request.bodyParameters()).length > 0)
53+
options.json = request.bodyParameters();
5854

59-
return rp(options)
60-
.then(this._parseResponse)
55+
return got(options)
56+
.json()
6157
.then((response)=> {
6258
return new Promise( (resolve) => {
6359
if (callback) { return callback(null, response); }
6460
return resolve(response);
6561
});
6662
})
67-
.catch(rp_errors.StatusCodeError,((error) => {
68-
throw new api_errors.ResponseError(request, error.statusCode, error.message);
63+
.catch((error) => {
64+
if (error instanceof got.HTTPError) {
65+
error = new api_errors.ResponseError(request, error.response.statusCode, error.response.body);
6966
}
70-
))
71-
.catch(rp_errors.RequestError,((error) => {
72-
if(error.cause.code === 'ETIMEDOUT' || error.cause.code === 'ESOCKETTIMEDOUT')
73-
throw new api_errors.TimeoutError(request, error);
74-
throw error;
67+
else if (error instanceof got.RequestError) {
68+
if(error.code === 'ETIMEDOUT' || error.code === 'ESOCKETTIMEDOUT') {
69+
error = new api_errors.TimeoutError(request, error);
70+
}
7571
}
76-
))
77-
.catch((error) => {
7872
if (callback) {return callback(error)};
7973
throw error;
8074
});
8175
}
8276

77+
_getRegionalBaseUri(region) {
78+
const uri = {
79+
'ap-se': 'rapi-ap-se.recombee.com',
80+
'ca-east': 'rapi-ca-east.recombee.com',
81+
'eu-west': 'rapi-eu-west.recombee.com',
82+
'us-west': 'rapi-us-west.recombee.com'
83+
}[region.toLowerCase()];
84+
85+
if (uri === undefined) {
86+
throw new Error(`Region "${region}" is unknown. You may need to update the version of the SDK.`)
87+
}
88+
89+
return uri;
90+
}
91+
92+
_getBaseUri() {
93+
let baseUri = process.env.RAPI_URI || this.options.baseUri;
94+
if (this.options.region) {
95+
if (baseUri) {
96+
throw new Error('baseUri and region cannot be specified at the same time');
97+
}
98+
baseUri = this._getRegionalBaseUri(this.options.region);
99+
}
100+
return baseUri || 'rapi.recombee.com';
101+
}
102+
83103
_buildRequestUrl(request) {
84-
let protocol = (request.ensureHttps || this.alwaysUseHttps) ? 'https' : 'http';
104+
let usedProtocol = (request.ensureHttps) ? 'https' : this.protocol;
85105
let reqUrl = request.path + this._encodeRequestQueryParams(request);
86106
let signedUrl = this._signUrl(reqUrl);
87-
return protocol + '://' + this.baseUri + signedUrl;
107+
return usedProtocol + '://' + this.baseUri + signedUrl;
88108
}
89109

90110
_encodeRequestQueryParams(request) {
@@ -161,14 +181,6 @@ class ApiClient {
161181
});
162182
}
163183

164-
_parseResponse(response) {
165-
return new Promise(
166-
function (resolve, reject) {
167-
resolve(response.body);
168-
}
169-
);
170-
}
171-
172184
_signUrl (req_part) {
173185
let url = '/' + this.databaseId + req_part;
174186
url += (req_part.indexOf("?") == -1 ? "?" : "&" ) + "hmac_timestamp=" + parseInt(new Date().getTime() / 1000);

Diff for: lib/requests/delete-item.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const rqs = require("./request");
88
/**
99
* Deletes an item of given `itemId` from the catalog.
1010
* 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.
11-
* 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.
11+
* 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.
1212
*/
1313
class DeleteItem extends rqs.Request {
1414

Diff for: lib/requests/delete-more-items.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
This file is auto-generated, do not edit
3+
*/
4+
5+
'use strict';
6+
const rqs = require("./request");
7+
8+
/**
9+
* Delete all the items that pass the filter.
10+
* 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.
11+
*/
12+
class DeleteMoreItems extends rqs.Request {
13+
14+
/**
15+
* Construct the request
16+
* @param {string} filter - A [ReQL](https://docs.recombee.com/reql.html) expression, which return `true` for the items that shall be updated.
17+
*/
18+
constructor(filter) {
19+
super('DELETE', '/more-items/', 1000, false);
20+
this.filter = filter;
21+
}
22+
23+
/**
24+
* Get body parameters
25+
* @return {Object} The values of body parameters (name of parameter: value of the parameter)
26+
*/
27+
bodyParameters() {
28+
let params = {};
29+
params.filter = this.filter;
30+
31+
return params;
32+
}
33+
34+
/**
35+
* Get query parameters
36+
* @return {Object} The values of query parameters (name of parameter: value of the parameter)
37+
*/
38+
queryParameters() {
39+
let params = {};
40+
return params;
41+
}
42+
}
43+
44+
exports.DeleteMoreItems = DeleteMoreItems

Diff for: lib/requests/delete-user.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class DeleteUser extends rqs.Request {
1313

1414
/**
1515
* Construct the request
16-
* @param {string} userId - ID of the user to be added.
16+
* @param {string} userId - ID of the user to be deleted.
1717
*/
1818
constructor(userId) {
1919
super('DELETE', `/users/${userId}`, 1000, false);

Diff for: lib/requests/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ exports.AddItemProperty = require("./add-item-property").AddItemProperty;
1212
exports.DeleteItemProperty = require("./delete-item-property").DeleteItemProperty;
1313
exports.GetItemPropertyInfo = require("./get-item-property-info").GetItemPropertyInfo;
1414
exports.ListItemProperties = require("./list-item-properties").ListItemProperties;
15+
exports.UpdateMoreItems = require("./update-more-items").UpdateMoreItems;
16+
exports.DeleteMoreItems = require("./delete-more-items").DeleteMoreItems;
1517
exports.AddSeries = require("./add-series").AddSeries;
1618
exports.DeleteSeries = require("./delete-series").DeleteSeries;
1719
exports.ListSeries = require("./list-series").ListSeries;
@@ -63,8 +65,6 @@ exports.RecommendItemsToItem = require("./recommend-items-to-item").RecommendIte
6365
exports.RecommendNextItems = require("./recommend-next-items").RecommendNextItems;
6466
exports.RecommendUsersToUser = require("./recommend-users-to-user").RecommendUsersToUser;
6567
exports.RecommendUsersToItem = require("./recommend-users-to-item").RecommendUsersToItem;
66-
exports.UserBasedRecommendation = require("./user-based-recommendation").UserBasedRecommendation;
67-
exports.ItemBasedRecommendation = require("./item-based-recommendation").ItemBasedRecommendation;
6868
exports.SearchItems = require("./search-items").SearchItems;
6969
exports.AddSearchSynonym = require("./add-search-synonym").AddSearchSynonym;
7070
exports.ListSearchSynonyms = require("./list-search-synonyms").ListSearchSynonyms;

0 commit comments

Comments
 (0)