Skip to content

Commit 724e90c

Browse files
author
Crhistian Ramirez
committed
✨ add axios CancelToken support
change last parameter accessToken to be a requestOptions object which lets us add cancelToken
1 parent 74a0087 commit 724e90c

86 files changed

Lines changed: 2905 additions & 4745 deletions

Some content is hidden

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

README.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ Me.As().ListProducts()
176176
.then(impersonatedProductList => console.log(impersonatedProductList))
177177
```
178178

179-
As you can see this method makes it very easy to toggle between impersonated calls and non-impersonated calls. But what if you have more than two tokens to toggle between? To address that scenario we recommend using the optional `accessToken` parameter available as the last parameter on all sdk methods.
179+
As you can see this method makes it very easy to toggle between impersonated calls and non-impersonated calls. But what if you have more than two tokens to toggle between? To address that scenario we recommend using the optional `requestOptions.accessToken` parameter. `requestOptions` is available as the last parameter on all sdk methods.
180180

181181
```javascript
182182
import { Me } from 'ordercloud-javascript-sdk';
@@ -186,18 +186,41 @@ var token2 = 'USER2_TOKEN';
186186
var token3 = 'USER3_TOKEN';
187187

188188
// Get products for user 1
189-
Me.ListProducts(null, token1)
189+
Me.ListProducts(null, { accessToken: token1 })
190190
.then(user1ProductList => console.log(user1ProductList))
191191

192192
// Get products for user 2
193-
Me.ListProducts(null, token2)
193+
Me.ListProducts(null, { accessToken: token2 })
194194
.then(user2ProductList => console.log(user2ProductList))
195195

196196
// Get products for user 3
197-
Me.ListProducts(null, token3)
197+
Me.ListProducts(null, { accessToken: token3 })
198198
.then(user3ProductList => console.log(user3ProductList))
199199
```
200200

201+
## Cancelling Requests
202+
203+
In addition to `requestOptions.accessToken` the sdk provides `requestOptions.cancelToken` which enables [axios request cancellation](https://github.com/axios/axios#cancellation). This option is useful for cleaning up outstanding requests when changes in your user experience no longer require the data requested. For instance, you could use the cancel token to clean up outstanding requests [when your react component unmounts](https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup).
204+
205+
```ts
206+
import axios from 'axios';
207+
import { Products } from 'ordercloud-javascript-sdk';
208+
209+
const signal = axios.CancelToken.source();
210+
211+
Products.List({search: 'Tennis balls'}, {cancelToken: signal.token})
212+
.catch(ex => {
213+
if (axios.isCancel(ex)) {
214+
console.log(ex) // 'This request was cancelled!'
215+
} else {
216+
console.log(ex) // Normal ordercloud exception
217+
}
218+
})
219+
220+
// Oops! I don't want to resolve this request anymore
221+
signal.cancel('This request was cancelled!')
222+
```
223+
201224
## Typescript Support
202225

203226
While typescript is not required to use this project (we compile it down to javascript for you), it does mean there are some added benefits for our typescript users.

codegen/templates/api/Auth.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import axios, { AxiosInstance } from 'axios'
1+
import axios, { AxiosInstance, CancelToken } from 'axios'
22
import { AccessToken } from '../models/AccessToken'
33
import Configuration from '../Configuration'
44
import { SecurityProfile } from '../models/SecurityProfile'
@@ -43,7 +43,10 @@ class Auth {
4343
username: string,
4444
password: string,
4545
clientID: string,
46-
scope: Array<SecurityProfile['Roles']>
46+
scope: Array<SecurityProfile['Roles']>,
47+
options: {
48+
cancelToken?: CancelToken
49+
} = {}
4750
): Promise<RequiredDeep<AccessToken>> {
4851
if (!Array.isArray(scope)) {
4952
throw new Error('scope must be a string array')
@@ -62,6 +65,7 @@ class Auth {
6265
'Content-Type': 'application/x-www-form-urlencoded',
6366
Accept: 'application/json',
6467
},
68+
...options,
6569
})
6670
.catch(e => {
6771
if (e.response) {
@@ -88,7 +92,10 @@ class Auth {
8892
username: string,
8993
password: string,
9094
clientID: string,
91-
scope: Array<SecurityProfile['Roles']>
95+
scope: Array<SecurityProfile['Roles']>,
96+
options: {
97+
cancelToken?: CancelToken
98+
} = {}
9299
): Promise<RequiredDeep<AccessToken>> {
93100
if (!Array.isArray(scope)) {
94101
throw new Error('scope must be a string array')
@@ -108,6 +115,7 @@ class Auth {
108115
'Content-Type': 'application/x-www-form-urlencoded',
109116
Accept: 'application/json',
110117
},
118+
...options,
111119
})
112120
.catch(e => {
113121
if (e.response) {
@@ -130,7 +138,10 @@ class Auth {
130138
public async ClientCredentials(
131139
clientSecret: string,
132140
clientID: string,
133-
scope: Array<SecurityProfile['Roles']>
141+
scope: Array<SecurityProfile['Roles']>,
142+
options: {
143+
cancelToken?: CancelToken
144+
} = {}
134145
): Promise<RequiredDeep<AccessToken>> {
135146
if (!Array.isArray(scope)) {
136147
throw new Error('scope must be a string array')
@@ -148,6 +159,7 @@ class Auth {
148159
'Content-Type': 'application/x-www-form-urlencoded',
149160
Accept: 'application/json',
150161
},
162+
...options,
151163
})
152164
.catch(e => {
153165
if (e.response) {
@@ -168,7 +180,10 @@ class Auth {
168180
*/
169181
public async RefreshToken(
170182
refreshToken: string,
171-
clientID: string
183+
clientID: string,
184+
options: {
185+
cancelToken?: CancelToken
186+
} = {}
172187
): Promise<RequiredDeep<AccessToken>> {
173188
const body = {
174189
grant_type: 'refresh_token',
@@ -182,6 +197,7 @@ class Auth {
182197
'Content-Type': 'application/x-www-form-urlencoded',
183198
Accept: 'application/json',
184199
},
200+
...options,
185201
})
186202
.catch(e => {
187203
if (e.response) {
@@ -202,7 +218,10 @@ class Auth {
202218
*/
203219
public async Anonymous(
204220
clientID: string,
205-
scope: Array<SecurityProfile['Roles']>
221+
scope: Array<SecurityProfile['Roles']>,
222+
options: {
223+
cancelToken?: CancelToken
224+
} = {}
206225
): Promise<RequiredDeep<AccessToken>> {
207226
if (!Array.isArray(scope)) {
208227
throw new Error('scope must be a string array')
@@ -219,6 +238,7 @@ class Auth {
219238
'Content-Type': 'application/x-www-form-urlencoded',
220239
Accept: 'application/json',
221240
},
241+
...options,
222242
})
223243
.catch(e => {
224244
if (e.response) {

codegen/templates/api/_RESOURCE_.ts.hbs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { {{this}} } from '../models/{{this}}';
44
import { PartialDeep } from '../models/PartialDeep';
55
import { RequiredDeep } from '../models/RequiredDeep';
66
import { Filters } from '../models/Filters';
7+
import { RequestOptions } from '../models/RequestOptions';
78
import httpClient from '../utils/HttpClient';
89
import OrderCloudError from '../utils/OrderCloudError';
910

@@ -22,13 +23,14 @@ class {{resource.id}} {
2223

2324
{{#resource.operations}}
2425
/**{{#allParams}}
25-
* @param {{#if isQueryParam}}options.{{name}} {{description}}{{else}}{{name}} {{description}}{{#if isBodyParam}}{{#if hasRequiredFields}}Required fields: {{commaSeparate requiredFields}}{{/if}}{{/if}}{{/if}}{{/allParams}}
26-
* @param accessToken Provide an alternative token to the one stored in the sdk instance (useful for impersonation).
26+
* @param {{#if isQueryParam}}listOptions.{{name}} {{description}}{{else}}{{name}} {{description}}{{#if isBodyParam}}{{#if hasRequiredFields}}Required fields: {{commaSeparate requiredFields}}{{/if}}{{/if}}{{/if}}{{/allParams}}
27+
* @param requestOptions.accessToken Provide an alternative token to the one stored in the sdk instance (useful for impersonation).
28+
* @param requestOptions.cancelToken Provide an [axios cancelToken](https://github.com/axios/axios#cancellation) that can be used to cancel the request.
2729
*/
28-
public async {{name}}{{#if hasReturnType}}{{#if isList}}<T{{baseType}} extends {{baseType}}>{{else}}<T{{returnType}} extends {{returnType}}>{{/if}}{{/if}}({{#allParams}}{{#unless isQueryParam}}{{#if isBodyParam}}{{#if ../isPatch}}{{name}}: PartialDeep<{{typescriptType}}>, {{else}}{{name}}: {{typescriptType}},{{/if}}{{else}}{{name}}: {{typescriptType}}, {{/if}}{{/unless}}{{/allParams}} {{#if hasQueryParams}}options: { {{#queryParams}}{{name}}?: {{typescriptType}}{{#unless @last}}, {{/unless}}{{/queryParams}} } = {}, {{/if}}accessToken?: string ): Promise<{{#if hasReturnType}}RequiredDeep<{{#if isList}}{{#if isFacetList}}ListPageFacet<T{{baseType}}>{{else}}ListPage<T{{baseType}}>{{/if}}{{else}}T{{returnType}}{{/if}}>{{else}}void{{/if}}> {
30+
public async {{name}}{{#if hasReturnType}}{{#if isList}}<T{{baseType}} extends {{baseType}}>{{else}}<T{{returnType}} extends {{returnType}}>{{/if}}{{/if}}({{#allParams}}{{#unless isQueryParam}}{{#if isBodyParam}}{{#if ../isPatch}}{{name}}: PartialDeep<{{typescriptType}}>, {{else}}{{name}}: {{typescriptType}},{{/if}}{{else}}{{name}}: {{typescriptType}}, {{/if}}{{/unless}}{{/allParams}} {{#if hasQueryParams}}options: { {{#queryParams}}{{name}}?: {{typescriptType}}{{#unless @last}}, {{/unless}}{{/queryParams}} } = {}, {{/if}}requestOptions: RequestOptions = {} ): Promise<{{#if hasReturnType}}RequiredDeep<{{#if isList}}{{#if isFacetList}}ListPageFacet<T{{baseType}}>{{else}}ListPage<T{{baseType}}>{{/if}}{{else}}T{{returnType}}{{/if}}>{{else}}void{{/if}}> {
2931
const impersonating = this.impersonating;
3032
this.impersonating = false;
31-
return await httpClient.{{verb}}(`{{parameterizePath path}}`{{#if hasBodyParam}}, {{bodyParam.name}}{{/if}}, { params: { {{#if hasQueryParams}}...options, {{/if}} {{#if hasFilters}}filters: options.filters, {{/if}}accessToken, impersonating } } )
33+
return await httpClient.{{verb}}(`{{parameterizePath path}}`{{#if hasBodyParam}}, {{bodyParam.name}}{{/if}}, { params: { {{#if hasQueryParams}}...options, {{/if}} {{#if hasFilters}}filters: options.filters, {{/if}}...requestOptions, impersonating } } )
3234
.catch(ex => {
3335
if(ex.response) {
3436
throw new OrderCloudError(ex)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { CancelToken } from 'axios'
2+
3+
export interface RequestOptions {
4+
accessToken?: string
5+
cancellationToken?: CancelToken
6+
}

codegen/templates/models/index.ts.hbs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ export * from './{{this.name}}';
44
export * from './DecodedToken';
55
export * from './SdkConfiguration';
66
export * from './PartialDeep';
7+
export * from './RequiredDeep';
78
export * from './ListPage';
89
export * from './ListPageFacet';
9-
export * from './Filters';
10+
export * from './Filters';
11+
export * from './RequestOptions';

docs/assets/js/search.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)