diff --git a/application/api/.eslintrc.json b/application/api/.eslintrc.json index 4f0fbb07..bb85d170 100644 --- a/application/api/.eslintrc.json +++ b/application/api/.eslintrc.json @@ -10,6 +10,7 @@ "db": "readonly", "bus": "readonly", "domain": "readonly", - "metarhia": "readonly" + "metarhia": "readonly", + "DomainError": "readonly" } } diff --git a/application/api/console.1/content.d.ts b/application/api/console.1/content.d.ts new file mode 100644 index 00000000..95abbf4a --- /dev/null +++ b/application/api/console.1/content.d.ts @@ -0,0 +1,8 @@ +namespace api.console.content { + type Code = 'ENOTFOUND' | 'EPARSE'; + + class CustomError extends DomainError { + constructor(code?: Code); + toJSON(): object; + } +} diff --git a/application/api/console.1/content.js b/application/api/console.1/content.js index 92b10df0..1eaec80f 100644 --- a/application/api/console.1/content.js +++ b/application/api/console.1/content.js @@ -1,9 +1,13 @@ ({ access: 'public', + async method({ name }) { + // Try type: new api.console.content.CustomError('EPARSE'); const filePath = `/content/${name}.md`; const buffer = application.resources.get(filePath); if (!buffer) return new Error('Content is not found'); return { text: buffer.toString() }; }, + + CustomError: class CustomError extends DomainError {}, }); diff --git a/application/api/example.1/add.d.ts b/application/api/example.1/add.d.ts new file mode 100644 index 00000000..2e583247 --- /dev/null +++ b/application/api/example.1/add.d.ts @@ -0,0 +1,8 @@ +namespace api.example.add { + type Code = 'EARGA' | 'EARGB'; + + class CustomError extends DomainError { + constructor(code?: Code); + toJSON(): object; + } +} diff --git a/application/api/example.1/add.js b/application/api/example.1/add.js index 080f3d2e..50f8be88 100644 --- a/application/api/example.1/add.js +++ b/application/api/example.1/add.js @@ -5,9 +5,40 @@ }, method: async ({ a, b }) => { + new api.example.add.CustomError('EARGA'); + if (typeof a !== 'number') return new DomainError('EARGA'); + if (typeof b !== 'number') { + return new api.example.example.CustomError('EARGB'); + } + if (Number.isNaN(a)) throw Error('Not a number: a'); + if (Number.isNaN(b)) throw Error('Not a number: b'); const result = a + b; return result; }, returns: 'number', + + errors: { + EARGA: 'Invalid argument: a', + EARGB: 'Invalid argument: b', + }, + + onError(error) { + if (error.code in this.errors) { + console.log(`Domain error detected: ${error.code}`); + } + return error; + }, + + onException(error) { + console.log(`Exception throws: ${error.message}`); + return error; + }, + + CustomError: class CustomError extends DomainError { + toJSON() { + const { name, code, message, stack } = this; + return { name, code, message, stack }; + } + }, }); diff --git a/types/global.d.ts b/types/global.d.ts index c30a8220..c9569bd3 100644 --- a/types/global.d.ts +++ b/types/global.d.ts @@ -23,3 +23,27 @@ declare global { const pg: Database; } } + +export interface ErrorOptions { + code?: number | string; + cause?: Error; +} + +export class Error extends global.Error { + constructor(message: string, options?: number | string | ErrorOptions); + message: string; + stack: string; + code?: number | string; + cause?: Error; +} + +type Errors = Record; + +export class DomainError extends Error { + constructor(code?: string, options?: number | string | ErrorOptions); + message: string; + stack: string; + code?: number | string; + cause?: Error; + toError(errors: Errors): Error; +}