{"action":"created","issue":{"url":"https://api.github.com/repos/vitaly-t/pg-promise/issues/107","repository_url":"https://api.github.com/repos/vitaly-t/pg-promise","labels_url":"https://api.github.com/repos/vitaly-t/pg-promise/issues/107/labels{/name}","comments_url":"https://api.github.com/repos/vitaly-t/pg-promise/issues/107/comments","events_url":"https://api.github.com/repos/vitaly-t/pg-promise/issues/107/events","html_url":"https://github.com/vitaly-t/pg-promise/issues/107","id":142631726,"number":107,"title":"[Custom Errors] A better way to handle exceptions","user":{"login":"vieks","id":9884533,"avatar_url":"https://avatars.githubusercontent.com/u/9884533?v=3","gravatar_id":"","url":"https://api.github.com/users/vieks","html_url":"https://github.com/vieks","followers_url":"https://api.github.com/users/vieks/followers","following_url":"https://api.github.com/users/vieks/following{/other_user}","gists_url":"https://api.github.com/users/vieks/gists{/gist_id}","starred_url":"https://api.github.com/users/vieks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vieks/subscriptions","organizations_url":"https://api.github.com/users/vieks/orgs","repos_url":"https://api.github.com/users/vieks/repos","events_url":"https://api.github.com/users/vieks/events{/privacy}","received_events_url":"https://api.github.com/users/vieks/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/vitaly-t/pg-promise/labels/question","name":"question","color":"cc317c"},{"url":"https://api.github.com/repos/vitaly-t/pg-promise/labels/suggestion","name":"suggestion","color":"bfd4f2"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":7,"created_at":"2016-03-22T12:11:39Z","updated_at":"2016-03-22T13:31:00Z","closed_at":null,"body":"First thanks a lot for your library which is amazing and gives off from shit bloated ORM.\r\n\r\nOne default is about errors handling in **our app** due to a limitation with the way how you have managed your Error objects inheritance inside **your lib**.\r\n\r\nFor instance:\r\n\r\n```javascript\r\n  async mutateAndGetPayload(payload, { rootValue: { req, db, cache, conf } }) {\r\n    try {\r\n      d(payload);\r\n\r\n      // validation: throws custom errors (an instance extended from Error class) on fail\r\n      const res = validator.check(payload, schema);\r\n      \r\n      payload.role       = role.BASIC;\r\n      payload.status     = status.UNREGISTERED;\r\n      payload.created_at = payload.updated_at = +new Date;\r\n      // throws also\r\n      payload.pass       = await bcrypt.hashAsync(payload.pass,\r\n                                                  conf.BCRYPT_ROUNDS);\r\n\r\n      // database: throws but a standard Error !!!\r\n      return await db.users.insert(payload);\r\n\r\n    } catch(error) {\r\n\r\n      // time to handle errors\r\n      let messages;\r\n\r\n      if(error instanceof ValidationError){\r\n        messages = validator.messages();\r\n      }else if(error instanceof BcryptError){\r\n        messages = '...';\r\n      }else if(error instanceof DatabaseError){ /* We can't right now pg-promise have not inherited Error */\r\n        messages = {\r\n          message: error.message,\r\n          detail: error.detail,\r\n          //...\r\n        };\r\n      }else{\r\n        // messages = ...\r\n      }\r\n\r\n      return messages;\r\n    }\r\n  },\r\n\r\n```\r\n\r\nAs you see, your lib only throws standard Errors, ``` error.contructor === Error``` and it become very tricky to handle them when many kind of errors from other libs can be thrown by the same try block. \r\n\r\nSo yeah there is solutions like isolating each portion of code sensitive to throw exception but the code will become messy and unpleasant to ready/follow.\r\n\r\nAnother way will be to make something like that on the error handler blocks: ``` else if('table' in error && 'constraint' in error) ... ``` but same problems, the code is ugly and harder to manage.\r\n\r\nThe clean solution is that you implement a bunch of custom extended Errors inherit from Error class, permitting to use/check them with ease.\r\n\r\n```javascript\r\n  if(error instanceof DatabaseConstraintViolationError){\r\n    // TODO\r\n  }else if(error instanceof DatabaseQueryError){\r\n     TODO    \r\n  }else if(error instanceof DatabaseError /* This is the common parent Error class of your lib */){\r\n    // TODO\r\n  }\r\n``` \r\nThe common parent Error class implementation is important to allow only one check for those do not want check them all.\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/vitaly-t/pg-promise/issues/comments/199815449","html_url":"https://github.com/vitaly-t/pg-promise/issues/107#issuecomment-199815449","issue_url":"https://api.github.com/repos/vitaly-t/pg-promise/issues/107","id":199815449,"user":{"login":"vieks","id":9884533,"avatar_url":"https://avatars.githubusercontent.com/u/9884533?v=3","gravatar_id":"","url":"https://api.github.com/users/vieks","html_url":"https://github.com/vieks","followers_url":"https://api.github.com/users/vieks/followers","following_url":"https://api.github.com/users/vieks/following{/other_user}","gists_url":"https://api.github.com/users/vieks/gists{/gist_id}","starred_url":"https://api.github.com/users/vieks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vieks/subscriptions","organizations_url":"https://api.github.com/users/vieks/orgs","repos_url":"https://api.github.com/users/vieks/repos","events_url":"https://api.github.com/users/vieks/events{/privacy}","received_events_url":"https://api.github.com/users/vieks/received_events","type":"User","site_admin":false},"created_at":"2016-03-22T13:31:00Z","updated_at":"2016-03-22T13:31:00Z","body":"Whatever you choose to do, big thanks for the hard work complete so far. Your lib is really nice and keep up the good work ;)"}}