-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(swap): Add code to ServiceError class [WEB-977] #654
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,7 +63,7 @@ const coerceChain = (chain: string) => { | |
case 'POLKADOT': | ||
return screamingSnakeToPascalCase(uppercase); | ||
default: | ||
throw ServiceError.badRequest(`invalid chain "${chain}"`); | ||
throw ServiceError.badRequest('bad-request', `invalid chain "${chain}"`); | ||
} | ||
}; | ||
|
||
|
@@ -126,7 +126,12 @@ router.get( | |
} | ||
} | ||
|
||
ServiceError.assert(swapDepositChannel || swap || failedSwap, 'notFound', 'resource not found'); | ||
ServiceError.assert( | ||
swapDepositChannel || swap || failedSwap, | ||
'notFound', | ||
'not-found', | ||
`no swap for id "${id}" found`, | ||
); | ||
|
||
let state: State; | ||
let failureMode; | ||
|
@@ -268,7 +273,7 @@ router.post( | |
const result = openSwapDepositChannelSchema.safeParse(req.body); | ||
if (!result.success) { | ||
logger.info('received bad request for new swap', { body: req.body }); | ||
throw ServiceError.badRequest('invalid request body'); | ||
throw ServiceError.badRequest('bad-request', 'invalid request body'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we provide more info as to which fields were invalid? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i was looking into generating a message for zod validation errors yesterday but decided to not include that in this pr bc it was not trivial. but i agree that it would be nice to give a hint about the validation error later on 🙂 |
||
} | ||
|
||
const { srcChainExpiryBlock, channelOpeningFee, ...response } = await openSwapDepositChannel( | ||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -5,30 +5,43 @@ type IgnoredField = | |||||||||
| 'prepareStackTrace' | ||||||||||
| 'stackTraceLimit'; | ||||||||||
|
||||||||||
type ErrorCode = 'not-found' | 'bad-request' | 'internal-error' | 'rpc-error' | 'invalid-amount'; | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i am not sure about the granularity here. eg an invalid address will lead to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the problem with the current approach is that we cannot really change from a general code ( we could add a third property ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TIL that there is a IETF RFC for exposing errors: https://datatracker.ietf.org/doc/html/rfc7807 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there even is a new RPC from 2023 that obsoletes the old one: https://datatracker.ietf.org/doc/html/rfc9457 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i am leaning to use the following format:
this would allow use to introduce specific error codes later on without breaking any consumer. (eg. adding a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this would be kinda similar to what stripe/twilio/square does: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we maybe just use numeric codes instead of keywords? Using keywords is an approach prone to collisions and the chances that we might need to change an old code (keyword) to be more/less explicit to accomodate a new error code is higher. Sorry if i am expressing this concern a little bit late. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Imagine using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i agree that this could lead to keywords being less explicit than they could be bc of backwards compatibility, a number would allow you to clarify the "meaning" later on. but this also means that the number itself does not give you an idea about the error (without consulting documentation). to solve that you could provide constants with meaningful names, but then you kinda end up with the same problem of not being able to change the constant name 🙈 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. about the second point i am not too concerned. i think it would be fine to return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think |
||||||||||
|
||||||||||
export default class ServiceError extends Error { | ||||||||||
static badRequest(message: string): ServiceError { | ||||||||||
return new ServiceError(message, 400); | ||||||||||
static badRequest( | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could be interesting to add a throw ServiceError.badRequest('some message').code('INVALID_AMOUNT') |
||||||||||
code: ErrorCode = 'bad-request', | ||||||||||
message = 'the request payload is not valid', | ||||||||||
Comment on lines
+12
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the message will specified more often than the code
Suggested change
|
||||||||||
): ServiceError { | ||||||||||
return new ServiceError(code, message, 400); | ||||||||||
} | ||||||||||
|
||||||||||
static notFound(message = 'resource not found'): ServiceError { | ||||||||||
return new ServiceError(message, 404); | ||||||||||
static notFound( | ||||||||||
code: ErrorCode = 'not-found', | ||||||||||
message = 'the requested resource was not found', | ||||||||||
): ServiceError { | ||||||||||
return new ServiceError(code, message, 404); | ||||||||||
} | ||||||||||
|
||||||||||
static internalError(message = 'internal error'): ServiceError { | ||||||||||
return new ServiceError(message, 500); | ||||||||||
static internalError( | ||||||||||
code: ErrorCode = 'internal-error', | ||||||||||
message = 'an unexpected internal error occurred', | ||||||||||
): ServiceError { | ||||||||||
return new ServiceError(code, message, 500); | ||||||||||
} | ||||||||||
|
||||||||||
static assert( | ||||||||||
condition: unknown, | ||||||||||
code: Exclude<keyof typeof ServiceError, IgnoredField>, | ||||||||||
type: Exclude<keyof typeof ServiceError, IgnoredField>, | ||||||||||
code: ErrorCode, | ||||||||||
message: string, | ||||||||||
): asserts condition { | ||||||||||
if (!condition) throw ServiceError[code](message); | ||||||||||
if (!condition) throw ServiceError[type](code, message); | ||||||||||
} | ||||||||||
|
||||||||||
constructor( | ||||||||||
readonly code: ErrorCode, | ||||||||||
message: string, | ||||||||||
readonly code: number, | ||||||||||
readonly httpCode: number, | ||||||||||
) { | ||||||||||
super(message); | ||||||||||
|
||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could be more explicit:
swap-not-found