Skip to content
This repository has been archived by the owner on Feb 6, 2024. It is now read-only.

Commit

Permalink
feat: error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
gigobyte committed May 11, 2020
1 parent 12dc704 commit 50dcdf1
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 44 deletions.
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@
"semantic-release": "semantic-release",
"start": "ts-node --transpile-only --pretty src",
"test": "jest",
"test:unit": "jest unit/",
"test:watch": "jest --watchAll"
},
"types": "lib/index.d.ts",
"dependencies": {
"@scaleleap/amazon-marketplaces": "^4.0.2",
"axios": "^0.19.2",
"fast-xml-parser": "^3.16.0",
"purify-ts": "^0.16.0-beta.1"
"purify-ts": "^0.16.0-beta.1",
"ts-error": "^1.0.4"
},
"devDependencies": {
"@scaleleap/config": "1.6.1",
Expand Down
72 changes: 37 additions & 35 deletions src/error.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,46 @@
/* eslint-disable max-classes-per-file */
export class MWSError extends Error {
constructor(...parameters: string[]) {
// Propagate some vendor-specific arguments
super(...parameters)

// If someone downlevels the compilation target to es5
Object.setPrototypeOf(this, MWSError.prototype)

// Maintains proper stack trace (only available on V8)
if (Error.captureStackTrace) {
Error.captureStackTrace(this, MWSError)
}
}
}
import { Codec, GetInterface, optional, string } from 'purify-ts/Codec'
import { ExtendableError } from 'ts-error'

export class HttpError extends MWSError {
public message = 'MWS: Encountered an error while sending a request: '
export class MWSError extends ExtendableError {}

constructor(public error: Error, ...parameters: string[]) {
super(...parameters)
this.message += error.message
Object.setPrototypeOf(this, HttpError.prototype)
export class HttpError extends MWSError {
public type!: string

if (Error.captureStackTrace) {
Error.captureStackTrace(this, HttpError)
}
}
}
public code!: string

export class ParsingError extends MWSError {
public message = 'MWS: Encountered an error while parsing a response: '
public detail!: string | undefined

constructor(public error: string, ...parameters: string[]) {
super(...parameters)
this.message += error
Object.setPrototypeOf(this, ParsingError.prototype)
public mwsMessage!: string

if (Error.captureStackTrace) {
Error.captureStackTrace(this, ParsingError)
}
}
public requestId!: string
}

export class ParsingError extends MWSError {}
/* eslint-enable max-classes-per-file */

export const MWSApiError = Codec.interface({
ErrorResponse: Codec.interface({
Error: Codec.interface({
Type: string,
Code: string,
Message: string,
Detail: optional(string),
}),
RequestId: string,
}),
})

type MWSApiError = GetInterface<typeof MWSApiError>

/* eslint-disable no-param-reassign */
export const enhanceError = (error: HttpError, response: MWSApiError): HttpError => {
error.type = response.ErrorResponse.Error.Type
error.code = response.ErrorResponse.Error.Code
error.detail = response.ErrorResponse.Error.Detail
error.mwsMessage = response.ErrorResponse.Error.Message
error.requestId = response.ErrorResponse.RequestId

return error
}
/* eslint-enable no-param-reassign */
23 changes: 17 additions & 6 deletions src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import axios from 'axios'
import parser from 'fast-xml-parser'
import { URLSearchParams } from 'url'

import { HttpError } from './error'
import { enhanceError, HttpError, MWSApiError } from './error'
import { sign } from './sign'

export interface MWSOptions {
Expand Down Expand Up @@ -88,10 +88,12 @@ const cleanParameters = (parameters: Parameters): CleanParameters =>
/* eslint-enable no-param-reassign */

const defaultFetch = ({ url, method, headers, data }: Request): Promise<RequestResponse> =>
axios({ method, url, headers, data }).then((response) => ({
data: response.data,
headers: response.headers,
}))
axios({ method, url, headers, data })
.then((response) => ({
data: response.data,
headers: response.headers,
}))
.catch((error) => error.response.data)

const parseResponse = <T>(response: RequestResponse): [T, RequestMeta] => {
const responseData = parser.parse(response.data)
Expand Down Expand Up @@ -162,7 +164,16 @@ export class HttpClient {
try {
return await this.fetch(config).then((x) => parseResponse(x))
} catch (error) {
throw new HttpError(error)
const response = MWSApiError.decode(parser.parse(error))

if (response.isRight()) {
throw enhanceError(
new HttpError(`Request failed with ${response.extract().ErrorResponse.Error.Code}`),
response.extract(),
)
}

throw error
}
}
}
8 changes: 8 additions & 0 deletions test/unit/__fixtures__/error-response.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<ErrorResponse xmlns="https://mws.amazonservices.com/Orders/2013-09-01">\n' +
<Error>
<Type>Sender</Type>
<Code>InvalidParameterValue</Code>
<Message>CreatedAfter or LastUpdatedAfter must be specified</Message>
</Error>
<RequestId>e26147f9-30cc-4379-9fb5-bd4ad966c48b</RequestId>
</ErrorResponse>
5 changes: 3 additions & 2 deletions test/unit/http.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { amazonMarketplaces, HttpClient, HttpError } from '../../src'
import { Resource } from '../../src/http'
import { getFixture } from '../utils'

describe('httpClient', () => {
it('should throw a HttpError on failure', async () => {
Expand All @@ -14,7 +15,7 @@ describe('httpClient', () => {
sellerId: '',
},
() => {
throw new Error('404')
throw getFixture('error-response')
},
)

Expand All @@ -25,6 +26,6 @@ describe('httpClient', () => {
action: 'GetServiceStatus',
parameters: {},
}),
).rejects.toStrictEqual(new HttpError(new Error('404')))
).rejects.toStrictEqual(new HttpError('Request failed with InvalidParameterValue'))
})
})

0 comments on commit 50dcdf1

Please sign in to comment.