Skip to content

Commit

Permalink
Added error hanling logic #44
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmytro Panontko committed Apr 25, 2019
1 parent 191ac98 commit 390938b
Show file tree
Hide file tree
Showing 11 changed files with 371 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"airbnb",
"plugin:jsx-a11y/recommended"
],
"globals": {
"Kit": true
},
"env": {
"node": true,
"browser": true,
Expand Down
3 changes: 3 additions & 0 deletions client/components/common/Navigation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const Navigation = () => (
<li role="menuitem">
<NavLink to="/form-components">Form components</NavLink>
</li>
<li role="menuitem">
<NavLink to="/example-components">Example page</NavLink>
</li>
</ul>
</div>
</nav>
Expand Down
30 changes: 30 additions & 0 deletions client/pages/Example.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { Component } from 'react';

import { Button } from 'Form';

class ExampleComponents extends Component {
state = {
error: '',
}

showError = () => {
fetch('/api/test/error')
.then(response => response.json())
.then(data => this.setState({ error: JSON.stringify(data) }));
}

render() {
const { error } = this.state;

return (
<div className="container">
<Button className="red" onClick={this.showError}>Show Error Message</Button>
<p>
{`Error: ${error}`}
</p>
</div>
);
}
}

export default ExampleComponents;
2 changes: 2 additions & 0 deletions client/routing/Routes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import MainLayout from 'Layout/Main';

import Index from 'Pages/Index';
import FormComponents from 'Pages/FormComponents';
import ExampleComponents from 'Pages/Example';
import NoMatch from 'Pages/NoMatch';

const Routes = () => (
Expand All @@ -13,6 +14,7 @@ const Routes = () => (
<Switch>
<Route path="/" component={Index} exact />
<Route path="/form-components" component={FormComponents} />
<Route path="/example-components" component={ExampleComponents} />
<Route component={NoMatch} />
</Switch>
</MainLayout>
Expand Down
128 changes: 128 additions & 0 deletions docs/error.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Error handling

This is a document how we most work with error on current project.

## Error handling

For correct works with `Error` in project please read [this article](https://expressjs.com/en/guide/error-handling.html) and use `Kit.CustomError` as `Error` object

Example of handling:

```js
router.get('/error', (req, res, next) => {
try {
// ...some code
} catch(e) {
next(new Kit.CustomError('UNAUTHORIZED_ACCESS', 401));
}
});
```

## Error structure

This structure you must send to client when error is happened and you can get this structure from `Kit.CustomError` by `.get` method

```js
{
"errors": [
{
"parameter": "start_time",
"details": "invalid date",
"code": "INVALID_PARAMETER",
"value": "",
"message": "Expected time, got \"\" for start_time"
}
],
"request": {
"params": {
"account_id": "hkk5"
}
},
"metadata": {}
}
```

## Error codes & what they mean

<table>
<thead>
<tr>
<th>HTTP Code</th>
<th>Error Code</th>
</tr>
</thead>
<tbody>
<tr>
<td>403</td>
<td>ACCOUNT_NOT_FOUND</td>
</tr>
<tr>
<td>403</td>
<td>ACTION_NOT_ALLOWED</td>
</tr>
<tr>
<td>400</td>
<td>EXCLUSIVE_PARAMETERS</td>
</tr>
<tr>
<td>400</td>
<td>FEATURE_NOT_AVAILABLE</td>
</tr>
<tr>
<td>400</td>
<td>ILLEGAL_CHARACTERS</td>
</tr>
<tr>
<td>500</td>
<td>INTERNAL_ERROR</td>
</tr>
<tr>
<td>400</td>
<td>INVALID_PARAMETER</td>
</tr>
<tr>
<td>400</td>
<td>INVALID_USER</td>
</tr>
<tr>
<td>400</td>
<td>INVALID_USER_ID</td>
</tr>
<tr>
<td>400</td>
<td>MISSING_PARAMETERS</td>
</tr>
<tr>
<td>404</td>
<td>NOT_FOUND</td>
</tr>
<tr>
<td>400</td>
<td>REQUEST_TOO_COMPLEX</td>
</tr>
<tr>
<td>404</td>
<td>ROUTE_NOT_FOUND</td>
</tr>
<tr>
<td>503</td>
<td>SERVICE_UNAVAILABLE</td>
</tr>
<tr>
<td>503</td>
<td>OVER_CAPACITY</td>
</tr>
<tr>
<td>429</td>
<td>TOO_MANY_REQUESTS</td>
</tr>
<tr>
<td>401</td>
<td>UNAUTHORIZED_ACCESS</td>
</tr>
<tr>
<td>403</td>
<td>USER_NOT_FOUND</td>
</tr>
</tbody>
</table>
97 changes: 97 additions & 0 deletions server/config/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
module.exports = {
ACCOUNT_NOT_FOUND: {
message: 'Account not found',
userMessage: 'Account not found',
code: 403,
},
ACTION_NOT_ALLOWED: {
message: 'Action not allowed',
userMessage: 'Action not allowed',
code: 403,
},
EXCLUSIVE_PARAMETERS: {
message: 'Exclusive parameters',
userMessage: 'Exclusive parameters',
code: 400,
},
FEATURE_NOT_AVAILABLE: {
message: 'Feature not available',
userMessage: 'Feature not available',
code: 400,
},
ILLEGAL_CHARACTERS: {
message: 'Illegal characters',
userMessage: 'Illegal characters',
code: 400,
},
INTERNAL_ERROR: {
message: 'Server error',
userMessage: 'Server error',
code: 500,
},
INVALID_PARAMETER: {
message: 'Invalid parameter',
userMessage: 'Invalid parameter',
code: 400,
},
INVALID_USER: {
message: 'Invalid user',
userMessage: 'Invalid user',
code: 400,
},
INVALID_USER_ID: {
message: 'Invalid user ID',
userMessage: 'Invalid user ID',
code: 400,
},
MISSING_PARAMETERS: {
message: 'Missing parameters',
userMessage: 'Missing parameters',
code: 400,
},
NOT_FOUND: {
message: 'Not Found',
userMessage: 'Not Found',
code: 404,
},
REQUEST_TOO_COMPLEX: {
message: 'Request too complex',
userMessage: 'Request too complex',
code: 400,
},
ROUTE_NOT_FOUND: {
message: 'Route not found',
userMessage: 'Route not found',
code: 404,
},
SERVICE_UNAVAILABLE: {
message: 'Service unavailable',
userMessage: 'Service unavailable',
code: 503,
},
OVER_CAPACITY: {
message: 'Over capacity',
userMessage: 'Over capacity',
code: 503,
},
TOO_MANY_REQUESTS: {
message: 'Too many request',
userMessage: 'Too many request',
code: 429,
},
UNAUTHORIZED_ACCESS: {
message: 'Unathorized access',
userMessage: 'Unathorized access',
code: 401,
},
USER_NOT_FOUND: {
message: 'User not found',
userMessage: 'User not found',
code: 403,
},
FORBIDDEN: {
message: 'Forbidden',
userMessage: 'Forbidden',
code: 403,
},
};
7 changes: 7 additions & 0 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@ const methodOverride = require('method-override');
const swaggerUIDist = require('swagger-ui-dist');

const routes = require('./routes/index.route');
const CustomError = require('./utils/error');
const errorHandler = require('./middlewares/error');

require('dotenv-safe').config();

global.Kit = {};
Kit.CustomError = CustomError;

const app = express();
app.db = require('./models');

Expand All @@ -35,6 +40,8 @@ if (!isProduction) {

app.get('/*', (req, res) => res.sendFile(path.join(__dirname, `../${isProduction ? 'dist' : 'client'}/index.html`)));

app.use(errorHandler);

const port = process.env.APP_PORT || 3001;
const host = process.env.APP_HOST || 'localhost';

Expand Down
19 changes: 19 additions & 0 deletions server/middlewares/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
function errorHandling(err, req, res, next) {
if (res.headersSent) {
return next(err);
}

res.status(err.code);
return res.json(err.get());
}

process.on('unhandledRejection', (err) => {
console.error(err);
});

process.on('uncaughtException', (err) => {
console.error(err);
process.exit(1);
});

module.exports = errorHandling;
6 changes: 6 additions & 0 deletions server/routes/index.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const express = require('express');

const authRoutes = require('./auth.route');
const userRoutes = require('./user.route');
// REMOVE_PROD: in real app you need remove this variable
const testRoutes = require('./test.route');

const router = express.Router();

Expand All @@ -11,4 +13,8 @@ router.use('/auth', authRoutes);
// mount user routes at /user
router.use('/user', userRoutes);

// REMOVE_PROD: in real app you need remove this route
router.use('/test', testRoutes);


module.exports = router;
9 changes: 9 additions & 0 deletions server/routes/test.route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const express = require('express');

const router = express.Router();

router.get('/error', (req, res, next) => {
next(new Kit.CustomError('UNAUTHORIZED_ACCESS', 401));
});

module.exports = router;
Loading

0 comments on commit 390938b

Please sign in to comment.