Last active
March 7, 2022 06:30
-
-
Save RohitRox/d0df7bdcf237ed3a4a50af9e9824eaed to your computer and use it in GitHub Desktop.
Beautiful Errors in Javascript
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
// Try/Catch Basics | |
try { | |
//something that causes an error | |
} catch (err){ | |
// error data | |
console.log(err.name) | |
console.log(err.message) | |
// checking for specific type | |
console.log(err instanceof(ReferenceError)) | |
} | |
// Example | |
try { | |
undefined+SOME_VARIABLE | |
} catch(err) { | |
// Javascript error types | |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types | |
console.log(err.name, err.message) | |
} | |
// Throwing errors in js | |
throw new Error("Not good.") | |
// Making our own beautiful errors | |
class TokenError extends Error { | |
constructor(message) { | |
super(message || 'Invalid Token'); | |
this.name = this.constructor.name; | |
if (typeof Error.captureStackTrace === 'function') { | |
Error.captureStackTrace(this, this.constructor); | |
} else { | |
this.stack = (new Error(message)).stack; | |
} | |
} | |
} | |
try { | |
throw new TokenError | |
// throw new TokenError("Expired Token") | |
} catch(err) { | |
console.log(err.name, err.message) | |
} | |
// Adding more data and info | |
class TokenExtendedError extends Error{ | |
constructor(message, params) { | |
super(message || 'Invalid Token'); | |
this.name = this.constructor.name; | |
this.code = params.code | |
if (typeof Error.captureStackTrace === 'function') { | |
Error.captureStackTrace(this, this.constructor); | |
} else { | |
this.stack = (new Error(message)).stack; | |
} | |
} | |
} | |
try { | |
throw new TokenExtendedError('Token is empty', { code: 'TokenEmptyError' }) | |
} catch(err) { | |
console.log(err.name, err.message, err.code, err instanceof(TokenExtendedError)) | |
} | |
// With the knowledge of custom error | |
// we now can design our own error types and | |
// catch and handle them accordingly | |
// and also set appropriate data/attributes for catching/logging/analyzing purposes | |
// we can also see that various standard libraries and sdk implements their own errors and presents us with their own error data and attributes | |
// For eg: with axios we get response attribute in error, which holds response data and status code | |
// aws sdk throws an error with code attribute | |
const axios = require('axios'); | |
// Handling axios errors | |
const callFetchPostsError = async () => { | |
try { | |
await axios.get('https://reqres.in/api/unknown/23'); | |
} catch (err) { | |
// handle error based on response data | |
if (err.response.data.message) { | |
console.log("Will do something with: ", err.response.data.message) | |
} else { | |
console.log("Oops! Something terribly went wrong. Prolly not axios Error.") | |
} | |
// handle error based on status codes | |
switch (err.response.status) { | |
case 404: | |
console.log("Server handled this but it's a not found.") | |
break; | |
case 500: | |
console.log("Server has no idea what's going on there.") | |
break; | |
default: | |
console.log("Something weird") | |
} | |
} | |
} | |
callFetchPostsError() | |
// Handling aws sdk error | |
// a fake aws sdk's function | |
const FakeAWSFunc = (success) => { | |
if (success) | |
return Promise.resolve({ some: 'data'}) | |
else | |
return Promise.reject( | |
new AWSError('Promise rejected', { code: 'NotAuthorizedException' }) | |
) | |
} | |
// fake aws custom error | |
class AWSError extends Error{ | |
constructor(message, params) { | |
super(message || 'AWS Error'); | |
this.name = this.constructor.name; | |
this.code = params.code | |
if (typeof Error.captureStackTrace === 'function') { | |
Error.captureStackTrace(this, this.constructor); | |
} else { | |
this.stack = (new Error(message)).stack; | |
} | |
} | |
} | |
const callFakeAWS = async () => { | |
try { | |
const data = await FakeAWSFunc(false); | |
console.log(data) | |
} catch(err) { | |
// handle specific error | |
if (['NotAuthorizedException', 'ValidationException'].includes(err.code)) { | |
console.log("I know what's going on. Will do thing accordingly.") | |
} else { | |
console.log("Have no idea. Prolly do a generic thing.") | |
} | |
// or handle based on type | |
if (err instanceof(AWSError)) { | |
} else { | |
} | |
} | |
} | |
callFakeAWS(); | |
// Handling multiple error types | |
const codeWithMultipleTypes = async () => { | |
try { | |
throw new TokenError | |
// error thrown from above line, code below this does not get executed, not .then blocks needed | |
const dd = await FakeAWSFunc() | |
} catch(err) { | |
// check here type of error anf handle accordingly | |
console.log(err instanceof(TokenError)) | |
console.log(err instanceof(AWSError)) | |
} | |
} | |
codeWithMultipleTypes() | |
// Testing | |
// Use mockImplementation in jest | |
// sucessfull operation | |
AWSService.associateSoftwareToken.mockImplementation(() => { | |
return Promise.resolve({}) | |
}) | |
// fail with code that identifies NotAuthorizedException error | |
AWSService.associateSoftwareToken.mockImplementation(() => { | |
return Promise.reject({ message: 'Message', code: 'NotAuthorizedException' }) | |
}) | |
// generic fail with just message | |
AWSService.associateSoftwareToken.mockImplementation(() => { | |
return Promise.reject({ message: 'Message' }) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment