Skip to content
Merged
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
3 changes: 2 additions & 1 deletion docs/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Pseudo-implementation of an alternative client:
import SDK, { Client } from '@uphold/uphold-sdk-javascript';

class AlternativeClient extends Client {
request(url, method, body, customHeaders = {}) {
request(url, method, body, customHeaders = {}, options) {
// Make your own implementation, but make sure it returns a Promise that resolves
// or rejects an object with the schema demonstrated at the bottom of this section.
}
Expand Down Expand Up @@ -53,6 +53,7 @@ This method is responsible for performing HTTP requests to Uphold's API.
| `method` | String | Yes | HTTP method |
| `body` | Object | Yes | Request body |
| `headers` | Object | No | Request headers |
| `options` | Object | No | Request options |

This method must resolve an object with the following schema so that pagination and errors can be handled in a proper fashion:

Expand Down
7 changes: 4 additions & 3 deletions src/browser/services/fetch-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { Client, createError } from '../../core';
import isHtml from 'is-html';

export default class FetchClient extends Client {
request(url, method = 'get', body, headers = {}) {
const options = {
request(url, method = 'get', body, headers = {}, options = {}) { // eslint-disable-line max-params
const requestOptions = {
...options,
body,
cache: 'no-cache',
credentials: 'omit',
Expand All @@ -15,7 +16,7 @@ export default class FetchClient extends Client {
mode: 'cors'
};

return fetch(url, options)
return fetch(url, requestOptions)
.then(response => {
if (!response.ok) {
return Promise.reject(response);
Expand Down
15 changes: 9 additions & 6 deletions src/core/sdk.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ export default class SDK {
this.oauthClient = new OAuthClient(this.options);
}

api(uri, { authenticate = true, body, headers = {}, method = 'get', queryParams, raw, version = this.options.version } = {}) {
api(uri, options = {}) {
const { authenticate = true, headers = {}, method = 'get', queryParams, raw, version = this.options.version } = options;
let { body } = options;

const url = buildUrl(uri, this.options.baseUrl, version, queryParams);

let request;
Expand All @@ -50,15 +53,15 @@ export default class SDK {
return this.client.request(url, method, body, {
...buildBearerAuthorizationHeader(tokens.access_token),
...headers
});
}, options);
});
} else {
request = this.client.request(url, method, body, headers);
request = this.client.request(url, method, body, headers, options);
}

return request
.then(data => { return raw ? data : data.body; })
.catch(this._refreshToken(url, method, body, headers));
.catch(this._refreshToken(url, method, body, headers, options));
}

authorize(code) {
Expand Down Expand Up @@ -134,7 +137,7 @@ export default class SDK {
.then(({ body }) => this.setToken(body));
}

_refreshToken(url, method, body, headers) {
_refreshToken(url, method, body, headers, options) { // eslint-disable-line max-params
return response => {
if (!response || !response.body || response.body.error !== 'invalid_token') {
return Promise.reject(response);
Expand All @@ -149,7 +152,7 @@ export default class SDK {
return this.client.request(url, method, body, {
...buildBearerAuthorizationHeader(tokens.access_token),
...headers
})
}, options)
.then(data => data.body);
});
};
Expand Down
3 changes: 2 additions & 1 deletion src/node/services/request-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { RequestError } from 'request-promise/errors';
import request from 'request-promise';

export default class RequestClient extends Client {
request(url, method, body, headers = {}) {
request(url, method, body, headers = {}, options) { // eslint-disable-line max-params
return request({
...options,
body,
headers: {
...this.defaultHeaders,
Expand Down
9 changes: 9 additions & 0 deletions test/browser/services/fetch-client.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ describe('FetchClient', () => {
});

describe('request()', () => {
it('should set `get` as default method if none is provided', () => {
fetchMock.mock('foo', {});

return client.request('foo')
.then(() => {
expect(fetchMock.lastOptions().method).toEqual('GET');
});
});

it('should send a `User-Agent` header', () => {
fetchMock.mock('foo', {});

Expand Down
35 changes: 23 additions & 12 deletions test/core/sdk.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ describe('SDK', () => {
return sdk.authorize('code')
.then(() => {
expect(sdk.client.request.mock.calls.length).toBe(1);
expect(sdk.client.request.mock.calls[0][1]).toBe('post');
expect(sdk.client.request.mock.calls[0][2]).toBe('client_id=foo&client_secret=bar&code=code&grant_type=authorization_code');
expect(sdk.client.request.mock.calls[0][3]).toEqual({ 'content-type': 'application/x-www-form-urlencoded' });
});
Expand Down Expand Up @@ -394,20 +395,22 @@ describe('SDK', () => {
'https://api.uphold.com/v0/foo',
'get',
undefined,
{ authorization: 'Bearer token' }
{ authorization: 'Bearer token' },
{}
);
});
});

it('should not build the `authorization` header if provided', () => {
it('should not build the `authorization` header if value is already provided', () => {
return sdk.api('/foo', { headers: { authorization: 'foo' } })
.then(() => {
expect(sdk.storage.getItem).not.toBeCalled();
expect(sdk.client.request).toBeCalledWith(
'https://api.uphold.com/v0/foo',
'get',
undefined,
{ authorization: 'foo' }
{ authorization: 'foo' },
{ headers: { authorization: 'foo' } }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the test name, this shouldn't be added, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name was wrong and confusing. Updated.

);
});
});
Expand All @@ -434,7 +437,8 @@ describe('SDK', () => {
'https://api.uphold.com/v0/foo',
'get',
undefined,
{}
{},
{ authenticate: false }
);
});
});
Expand Down Expand Up @@ -471,31 +475,38 @@ describe('SDK', () => {

it('should add custom headers', () => {
sdk.client.request.mockReturnValue(Promise.resolve('foo'));
const options = { authenticate: false, headers: { foo: 'bar' } };

return sdk.api('/biz', { authenticate: false, headers: { foo: 'bar' } })
return sdk.api('/biz', options)
.then(() => {
expect(sdk.client.request).toBeCalledWith('https://api.uphold.com/v0/biz', 'get', undefined, { foo: 'bar' });
expect(sdk.client.request).toBeCalledWith('https://api.uphold.com/v0/biz', 'get', undefined, { foo: 'bar' }, options);
});
});

it('should build the request url with configured version if `version` is not provided', () => {
return sdk.api('/foo', { authenticate: false })
const options = { authenticate: false };

return sdk.api('/foo', options)
.then(() => {
expect(sdk.client.request).toBeCalledWith('https://api.uphold.com/v0/foo', 'get', undefined, {});
expect(sdk.client.request).toBeCalledWith('https://api.uphold.com/v0/foo', 'get', undefined, {}, options);
});
});

it('should build the request url with given `version`', () => {
return sdk.api('/foo', { authenticate: false, version: 'bar' })
const options = { authenticate: false, version: 'bar' };

return sdk.api('/foo', options)
.then(() => {
expect(sdk.client.request).toBeCalledWith('https://api.uphold.com/bar/foo', 'get', undefined, {});
expect(sdk.client.request).toBeCalledWith('https://api.uphold.com/bar/foo', 'get', undefined, {}, options);
});
});

it('should build the request url with no version if `version` is given as `false`', () => {
return sdk.api('/foo', { authenticate: false, version: false })
const options = { authenticate: false, version: false };

return sdk.api('/foo', options)
.then(() => {
expect(sdk.client.request).toBeCalledWith('https://api.uphold.com/foo', 'get', undefined, {});
expect(sdk.client.request).toBeCalledWith('https://api.uphold.com/foo', 'get', undefined, {}, options);
});
});
});
Expand Down
Loading