-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[tweek-client] add client error handling (#147)
* add tweek client with fallback * add deprecated decorator to fetch use getValue instead * add TweekClientWithFallback tests * use $includeErrors * add option to throw on key errors * bump version * fix repo tests * call onKeyError for each failed key * cr
- Loading branch information
Showing
20 changed files
with
403 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { KeyValuesErrors } from './types'; | ||
|
||
export class KeyValuesError extends Error { | ||
constructor(keyValuesErrors: KeyValuesErrors, message: string); | ||
constructor(public keyValuesErrors: KeyValuesErrors, ...args: any[]) { | ||
super(...args); | ||
|
||
Object.setPrototypeOf(this, KeyValuesError.prototype); | ||
|
||
if (Error.captureStackTrace) { | ||
Error.captureStackTrace(this, KeyValuesError); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
js/tweek-client/src/TweekClient/TweekClientWithFallback.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { GetValuesConfig, ITweekClient } from './types'; | ||
|
||
export default class TweekClientWithFallback implements ITweekClient { | ||
constructor(private readonly _clients: ITweekClient[]) {} | ||
|
||
getValues<T>(path: string, config: GetValuesConfig): Promise<T> { | ||
return this._execute(client => client.getValues(path, config)); | ||
} | ||
|
||
fetch<T>(path: string, config?: GetValuesConfig): Promise<T> { | ||
return this._execute(client => client.fetch(path, config)); | ||
} | ||
|
||
private _execute<T>(fn: (client: ITweekClient) => Promise<T>): Promise<T> { | ||
return this._clients.reduce((acc, client) => acc.catch(() => fn(client)), Promise.reject( | ||
new Error('TweekClientWithFallback has no clients'), | ||
) as Promise<T>); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
js/tweek-client/src/TweekClient/createTweekClientWithFallback.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { createTweekClient } from './createTweekClient'; | ||
import TweekClientWithFallback from './TweekClientWithFallback'; | ||
import { BaseCreateTweekClientConfig } from './types'; | ||
|
||
export type CreateTweekClientConfigWithFallback = BaseCreateTweekClientConfig & { | ||
urls: string[]; | ||
}; | ||
|
||
export function createTweekClientWithFallback({ urls, ...config }: CreateTweekClientConfigWithFallback) { | ||
const clients = urls.map(baseServiceUrl => createTweekClient({ baseServiceUrl, ...config })); | ||
return new TweekClientWithFallback(clients); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
export * from './types'; | ||
export { default as TweekClient } from './TweekClient'; | ||
export { default as TweekClientWithFallback } from './TweekClientWithFallback'; | ||
export * from './createTweekClient'; | ||
export * from './createTweekClientWithFallback'; | ||
export * from './KeyValuesError'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 9 additions & 2 deletions
11
js/tweek-client/src/TweekManagementClient/createTweekManagementClient.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import sinon from 'sinon'; | ||
import { expect } from 'chai'; | ||
import { KeyValuesError, TweekClient } from '../../src'; | ||
|
||
describe('TweekClient errorHandling', () => { | ||
let fetchStub: sinon.SinonStub; | ||
let onKeyError: sinon.SinonStub; | ||
let tweekClient: TweekClient; | ||
|
||
beforeEach(() => { | ||
fetchStub = sinon.stub(); | ||
onKeyError = sinon.stub(); | ||
}); | ||
|
||
describe('onKeyValueError', () => { | ||
beforeEach(() => { | ||
tweekClient = new TweekClient({ | ||
baseServiceUrl: '', | ||
fetch: fetchStub, | ||
onKeyValueError: onKeyError, | ||
}); | ||
}); | ||
|
||
it('should not call onKeyValueError if errors is not in the response body', async () => { | ||
fetchStub.resolves(new Response(JSON.stringify({}))); | ||
|
||
await tweekClient.getValues(''); | ||
|
||
sinon.assert.notCalled(onKeyError); | ||
}); | ||
|
||
it('should not call onKeyValueError if errors object is empty', async () => { | ||
fetchStub.resolves(new Response(JSON.stringify({ errors: {} }))); | ||
|
||
await tweekClient.getValues(''); | ||
|
||
sinon.assert.notCalled(onKeyError); | ||
}); | ||
|
||
it('should call onKeyValueError if errors object contains errors', async () => { | ||
const errors = { | ||
some_key: 'some error', | ||
other_key: 'other error', | ||
}; | ||
fetchStub.resolves(new Response(JSON.stringify({ errors }))); | ||
|
||
await tweekClient.getValues(''); | ||
|
||
Object.entries(errors).forEach(([keyPath, error]) => sinon.assert.calledWithExactly(onKeyError, keyPath, error)); | ||
}); | ||
}); | ||
|
||
describe('throwOnError', () => { | ||
beforeEach(() => { | ||
tweekClient = new TweekClient({ | ||
baseServiceUrl: '', | ||
fetch: fetchStub, | ||
throwOnError: true, | ||
}); | ||
}); | ||
|
||
it('should not throw if errors is not in the response body', async () => { | ||
fetchStub.resolves(new Response(JSON.stringify({}))); | ||
|
||
await tweekClient.getValues(''); | ||
}); | ||
|
||
it('should not throw if errors object is empty', async () => { | ||
fetchStub.resolves(new Response(JSON.stringify({ errors: {} }))); | ||
|
||
await tweekClient.getValues(''); | ||
}); | ||
|
||
it('should throw if errors object contains errors', async () => { | ||
const errors = { some_key: 'some error' }; | ||
fetchStub.resolves(new Response(JSON.stringify({ errors }))); | ||
|
||
await expect(tweekClient.getValues('')).to.be.rejectedWith(KeyValuesError); | ||
}); | ||
}); | ||
|
||
it('should throw and call onKeyValueError if both are defined', async () => { | ||
const keyPath = 'some_key'; | ||
const error = 'some error'; | ||
|
||
tweekClient = new TweekClient({ | ||
baseServiceUrl: '', | ||
fetch: fetchStub, | ||
onKeyValueError: onKeyError, | ||
throwOnError: true, | ||
}); | ||
|
||
fetchStub.resolves(new Response(JSON.stringify({ errors: { [keyPath]: error } }))); | ||
|
||
await expect(tweekClient.getValues('')).to.be.rejectedWith(KeyValuesError); | ||
|
||
sinon.assert.calledOnce(onKeyError); | ||
sinon.assert.calledWithExactly(onKeyError, keyPath, error); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.