From b45ec446556c9f5240be1b00aebc50d7f6fed39c Mon Sep 17 00:00:00 2001 From: phoebe-lew Date: Wed, 22 Nov 2023 18:44:34 +1100 Subject: [PATCH] Handle http-server callback errors and pass offering to RFQ handler (#91) * Handle http-server callback errors and introduce options to `SubmitCallback` --------- Co-authored-by: Moe Jangda --- .changeset/omega-carrots-sort.md | 6 ++++++ .changeset/tiny-carrots-sort.md | 5 ----- .../src/request-handlers/callback-error.ts | 20 +++++++++++++++++++ .../http-server/src/request-handlers/index.ts | 1 + .../src/request-handlers/submit-close.ts | 11 +++++++--- .../src/request-handlers/submit-order.ts | 11 +++++++--- .../src/request-handlers/submit-rfq.ts | 11 +++++++--- packages/http-server/src/types.ts | 12 ++++++++++- packages/protocol/build/compile-validators.js | 2 +- 9 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 .changeset/omega-carrots-sort.md delete mode 100644 .changeset/tiny-carrots-sort.md create mode 100644 packages/http-server/src/request-handlers/callback-error.ts diff --git a/.changeset/omega-carrots-sort.md b/.changeset/omega-carrots-sort.md new file mode 100644 index 00000000..b14c6701 --- /dev/null +++ b/.changeset/omega-carrots-sort.md @@ -0,0 +1,6 @@ +--- +"@tbdex/http-server": minor +--- + +* Restructure error messages as ErrorDetail type +* Handle http-server callback errors and pass offering to RFQ handler diff --git a/.changeset/tiny-carrots-sort.md b/.changeset/tiny-carrots-sort.md deleted file mode 100644 index c48161c1..00000000 --- a/.changeset/tiny-carrots-sort.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@tbdex/http-server": patch ---- - -Restructure error messages as ErrorDetail type diff --git a/packages/http-server/src/request-handlers/callback-error.ts b/packages/http-server/src/request-handlers/callback-error.ts new file mode 100644 index 00000000..94d606b6 --- /dev/null +++ b/packages/http-server/src/request-handlers/callback-error.ts @@ -0,0 +1,20 @@ +import type { ErrorDetail } from '@tbdex/http-client' + +export class CallbackError extends Error { + public readonly statusCode: number + public readonly details: ErrorDetail[] + + constructor(statusCode: number, details: ErrorDetail[] = []) { + super() + + this.name = this.constructor.name + this.statusCode = statusCode + this.details = details + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor) + } + + Object.setPrototypeOf(this, CallbackError.prototype) + } +} \ No newline at end of file diff --git a/packages/http-server/src/request-handlers/index.ts b/packages/http-server/src/request-handlers/index.ts index 15092813..d474d9c9 100644 --- a/packages/http-server/src/request-handlers/index.ts +++ b/packages/http-server/src/request-handlers/index.ts @@ -1,3 +1,4 @@ +export * from './callback-error.js' export * from './get-exchanges.js' export * from './get-offerings.js' export * from './submit-close.js' diff --git a/packages/http-server/src/request-handlers/submit-close.ts b/packages/http-server/src/request-handlers/submit-close.ts index 265f329d..ae71292e 100644 --- a/packages/http-server/src/request-handlers/submit-close.ts +++ b/packages/http-server/src/request-handlers/submit-close.ts @@ -3,6 +3,7 @@ import type { ErrorDetail } from '@tbdex/http-client' import type { MessageKind } from '@tbdex/protocol' import { Message } from '@tbdex/protocol' +import { CallbackError } from './index.js' type SubmitCloseOpts = { callback: SubmitCallback<'close'> @@ -37,11 +38,15 @@ export function submitClose(opts: SubmitCloseOpts): RequestHandler { } try { - // TODO: figure out what to do with callback result, if anything. (issue #12) - const _result = await callback({ request: req, response: res }, message) + await callback({ request: req, response: res }, message, undefined) return res.sendStatus(202) } catch(e) { - // TODO: handle error lewl (issue #3) + if (e instanceof CallbackError) { + return res.status(e.statusCode).json({ errors: e.details }) + } else { + const errorDetail: ErrorDetail = { detail: 'umm idk' } + return res.status(500).json({ errors: [errorDetail] }) + } } } } \ No newline at end of file diff --git a/packages/http-server/src/request-handlers/submit-order.ts b/packages/http-server/src/request-handlers/submit-order.ts index 37c067c6..11234dc6 100644 --- a/packages/http-server/src/request-handlers/submit-order.ts +++ b/packages/http-server/src/request-handlers/submit-order.ts @@ -3,6 +3,7 @@ import type { ErrorDetail } from '@tbdex/http-client' import type { MessageKind } from '@tbdex/protocol' import { Message } from '@tbdex/protocol' +import { CallbackError } from './index.js' type SubmitOrderOpts = { callback: SubmitCallback<'order'> @@ -40,11 +41,15 @@ export function submitOrder(opts: SubmitOrderOpts): RequestHandler { } try { - // TODO: figure out what to do with callback result, if anything. (#issue 5) - const _result = await callback({ request: req, response: res }, message) + await callback({ request: req, response: res }, message, undefined) return res.sendStatus(202) } catch(e) { - // TODO: handle error lewl + if (e instanceof CallbackError) { + return res.status(e.statusCode).json({ errors: e.details }) + } else { + const errorDetail: ErrorDetail = { detail: 'umm idk' } + return res.status(500).json({ errors: [errorDetail] }) + } } } } \ No newline at end of file diff --git a/packages/http-server/src/request-handlers/submit-rfq.ts b/packages/http-server/src/request-handlers/submit-rfq.ts index 2f75ab53..868bc1c9 100644 --- a/packages/http-server/src/request-handlers/submit-rfq.ts +++ b/packages/http-server/src/request-handlers/submit-rfq.ts @@ -3,6 +3,7 @@ import type { MessageKind } from '@tbdex/protocol' import type { ErrorDetail } from '@tbdex/http-client' import { Message } from '@tbdex/protocol' +import { CallbackError } from './index.js' type SubmitRfqOpts = { callback: SubmitCallback<'rfq'> @@ -53,10 +54,14 @@ export function submitRfq(options: SubmitRfqOpts): RequestHandler { } try { - // TODO: figure out what to do with callback result, if anything. (issue #7) - const _result = await callback({ request: req, response: res }, message) + await callback({ request: req, response: res }, message, { offering }) } catch(e) { - // TODO: handle error lewl (#issue 8) + if (e instanceof CallbackError) { + return res.status(e.statusCode).json({ errors: e.details }) + } else { + const errorDetail: ErrorDetail = { detail: 'umm idk' } + return res.status(500).json({ errors: [errorDetail] }) + } } return res.sendStatus(202) diff --git a/packages/http-server/src/types.ts b/packages/http-server/src/types.ts index 75ab35c2..5cf06aa8 100644 --- a/packages/http-server/src/types.ts +++ b/packages/http-server/src/types.ts @@ -28,11 +28,21 @@ export type GetCallbacks = { */ export type SubmitKind = 'rfq' | 'order' | 'close' +/** + * Types for options provided to {@link SubmitCallback} + * @beta + */ +export type SubmitCallbackOpts = { + 'rfq': { offering: Offering } + 'order': undefined + 'close': undefined +} + /** * Callback handler for the submit requests * @beta */ -export type SubmitCallback = (ctx: RequestContext, message: MessageKindClasses[T]) => any +export type SubmitCallback = (ctx: RequestContext, message: MessageKindClasses[T], opts: SubmitCallbackOpts[T]) => Promise /** * Map of callbacks handlers for the submit requests diff --git a/packages/protocol/build/compile-validators.js b/packages/protocol/build/compile-validators.js index db30ad87..6194831f 100644 --- a/packages/protocol/build/compile-validators.js +++ b/packages/protocol/build/compile-validators.js @@ -17,7 +17,7 @@ import standaloneCode from 'ajv/dist/standalone/index.js' import { mkdirp } from 'mkdirp' -const schemaHostUrl = 'https://tbdex.dev' +const schemaHostUrl = 'https://tbdex.dev/json-schemas' const schemaUrls = { definitions : `${schemaHostUrl}/definitions.json`, resource : `${schemaHostUrl}/resource.schema.json`,