@mendeley/api
Advanced tools
Comparing version 6.3.0 to 6.3.2
{ | ||
"name": "mendeley-javascript-sdk", | ||
"version": "6.3.0", | ||
"version": "6.3.2", | ||
"description": "Mendeley API JavaScript SDK", | ||
@@ -5,0 +5,0 @@ "repository": { |
@@ -65,2 +65,3 @@ 'use strict'; | ||
retrieve: utils.requestFun({ | ||
responseFilter: utils.passFilter, | ||
authFlow: options.authFlow, | ||
@@ -70,3 +71,4 @@ baseUrl: options.baseUrl, | ||
resource: '/files/{id}', | ||
args: ['id'] | ||
args: ['id'], | ||
noFollow: true | ||
}), | ||
@@ -73,0 +75,0 @@ |
@@ -35,4 +35,9 @@ 'use strict'; | ||
if (!token) { | ||
this.authRetries++; | ||
return refreshToken.call(this); | ||
if (this.authRetries < this.settings.maxAuthRetries) { | ||
this.authRetries++; | ||
return refreshToken.call(this); | ||
} else { | ||
this.settings.authFlow.authenticate(); | ||
throw new Error('maxAuthRetries exceeded'); | ||
} | ||
} | ||
@@ -39,0 +44,0 @@ |
@@ -15,2 +15,3 @@ 'use strict'; | ||
module.exports = { | ||
passFilter: passFilter, | ||
requestFun: requestFun, | ||
@@ -22,2 +23,15 @@ requestWithDataFun: requestWithDataFun, | ||
/** | ||
* Pass the second argument as it is. This is to allow receiving non-standard | ||
* API responses (no 'data' property in response body). | ||
* | ||
* @param {object} options Additional options, ignored in this case | ||
* @param {object} response Response body | ||
* @returns {object} Untouched response body | ||
*/ | ||
function passFilter(options, response) { | ||
return response; | ||
} | ||
function dataFilter(options, response) { | ||
@@ -36,2 +50,15 @@ return response.data; | ||
/** | ||
* Determines of the HTTP request was successful or not based on the response | ||
* HTTP result code. This is to allow treating HTTP redirects as successful as | ||
* axios handles them as failed by default. | ||
* | ||
* @private | ||
* @param {number} status HTTP status code number | ||
* @returns {bool} Result says if the request was successful or not | ||
*/ | ||
function allowRedirectHttpCodes(status) { | ||
return status >= 200 && status < 400; | ||
} | ||
/** | ||
* A general purpose request functions | ||
@@ -63,2 +90,7 @@ * | ||
if (options.noFollow) { | ||
request.maxRedirects = 0; | ||
request.validateStatus = allowRedirectHttpCodes; | ||
} | ||
var settings = { | ||
@@ -65,0 +97,0 @@ authFlow: options.authFlow() |
{ | ||
"name": "@mendeley/api", | ||
"version": "6.3.0", | ||
"version": "6.3.2", | ||
"description": "Mendeley API JavaScript SDK", | ||
@@ -5,0 +5,0 @@ "directories": { |
@@ -97,2 +97,73 @@ /* jshint sub: true */ | ||
describe('retrieve method', function() { | ||
var ajaxSpy; | ||
var ajaxRequest; | ||
var responsePromise; | ||
var sampleResponse = { | ||
headers: {} | ||
}; | ||
it('be defined', function(done) { | ||
expect(typeof filesApi.retrieve).toBe('function'); | ||
ajaxSpy = spyOn(axios, 'request').and.returnValue(Bluebird.resolve(sampleResponse)); | ||
responsePromise = filesApi.retrieve('someId').finally(function() { | ||
expect(ajaxSpy).toHaveBeenCalled(); | ||
ajaxRequest = ajaxSpy.calls.mostRecent().args[0]; | ||
done(); | ||
}); | ||
}); | ||
it('should use GET', function() { | ||
expect(ajaxRequest.method).toBe('get'); | ||
}); | ||
it('should use endpoint /files?document_id=someId', function() { | ||
expect(ajaxRequest.url).toBe(baseUrl + '/files/someId'); | ||
}); | ||
it('should have an Accept header', function() { | ||
expect(ajaxRequest.headers['Accept']).toBeDefined(); | ||
}); | ||
it('should NOT have a Content-Type header', function() { | ||
expect(ajaxRequest.headers['Content-Type']).not.toBeDefined(); | ||
}); | ||
it('should have an Authorization header', function() { | ||
expect(ajaxRequest.headers.Authorization).toBeDefined(); | ||
expect(ajaxRequest.headers.Authorization).toBe('Bearer auth'); | ||
}); | ||
it('should NOT unpack the response envelope', function(done) { | ||
responsePromise.then(function(response) { | ||
expect(JSON.stringify(response)).toEqual(JSON.stringify(sampleResponse)); | ||
done(); | ||
}); | ||
}); | ||
it('should not follow HTTP redirects', function() { | ||
expect(typeof filesApi.retrieve).toBe('function'); | ||
ajaxSpy = spyOn(axios, 'request').and.returnValue(Bluebird.resolve({headers: {}})); | ||
filesApi.retrieve('someId'); | ||
var requestArgs = ajaxSpy.calls.first().args[0]; | ||
expect(requestArgs.maxRedirects).toEqual(0); | ||
}); | ||
it('should handle HTTP redirects like successful response', function() { | ||
expect(typeof filesApi.retrieve).toBe('function'); | ||
ajaxSpy = spyOn(axios, 'request').and.returnValue(Bluebird.resolve({headers: {}})); | ||
filesApi.retrieve('someId'); | ||
var requestArgs = ajaxSpy.calls.first().args[0]; | ||
var isStatusSuccessFunc = requestArgs.validateStatus; | ||
expect(isStatusSuccessFunc(303)).toEqual(true); | ||
}); | ||
}); | ||
describe('list method', function() { | ||
@@ -99,0 +170,0 @@ var ajaxSpy; |
@@ -118,2 +118,19 @@ 'use strict'; | ||
it('should NOT exceed maxAuthRetries for multiple requests', function(done) { | ||
var mockAuthInterface = mockAuth.slowAuthCodeFlow(); | ||
var ajaxSpy = spyOn(axios, 'request').and.returnValue(Bluebird.reject(mockAuth.unauthorisedError)); | ||
var authRefreshSpy = spyOn(mockAuthInterface, 'refreshToken').and.callThrough(); | ||
var authAuthenticateSpy = spyOn(mockAuthInterface, 'authenticate').and.callThrough(); | ||
Bluebird.all([ | ||
request.create({ method: 'get' }, { authFlow: mockAuthInterface }).send(), | ||
request.create({ method: 'get' }, { authFlow: mockAuthInterface }).send() | ||
]).catch(function() { | ||
expect(ajaxSpy.calls.count()).toEqual(1); | ||
expect(authRefreshSpy.calls.count()).toEqual(1); | ||
expect(authAuthenticateSpy.calls.count()).toEqual(1); | ||
done(); | ||
}); | ||
}); | ||
it('should not make multiple concurrent requests to refresh an access token', function(done) { | ||
@@ -120,0 +137,0 @@ var mockAuthInterface = mockAuth.slowAuthCodeFlow(); |
1512251
15241