Skip to content

Commit

Permalink
added improved error handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
Morgul committed May 21, 2024
1 parent be549ee commit c0e3a16
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 34 deletions.
26 changes: 19 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
"trivialperms": "^2.0.0-beta.0",
"ts-essentials": "^10.0.0",
"zod": "^3.23.8",
"zod-express-middleware": "^1.4.0"
"zod-express": "^0.0.8",
"zod-validation-error": "^3.3.0"
},
"devDependencies": {
"@ckpack/vue-color": "^1.3.0",
Expand Down Expand Up @@ -88,7 +89,7 @@
"vue-router": "^4.1.6"
},
"overrides": {
"zod-express-middleware": {
"zod-express": {
"express": "$express"
}
},
Expand Down
43 changes: 43 additions & 0 deletions src/server/engines/validation/express.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// ---------------------------------------------------------------------------------------------------------------------
// Express Validation Tools
// ---------------------------------------------------------------------------------------------------------------------

import { Request, Response, NextFunction } from 'express';

import { fromError } from 'zod-validation-error';

// ---------------------------------------------------------------------------------------------------------------------

export function validationErrorHandler(err : any, req : Request, res : Response, next : NextFunction) : void
{
if(Array.isArray(err))
{
const errors = err.map((errObj) =>
{
return {
...errObj,
errors: fromError(errObj.errors)
};
});

if(errors.length > 0)
{
const errorMsg = errors.map((errObj) =>
{
return `${ errObj.type }: ${ errObj.errors.toString() }`;
});

res.status(422).json({
message: `Request Validation Failed: ${ errorMsg.join('\n') }`,
errors
});

// Return to not call next
return;
}
}

next(err);
}

// ---------------------------------------------------------------------------------------------------------------------
74 changes: 49 additions & 25 deletions src/server/routes/accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@
//----------------------------------------------------------------------------------------------------------------------

import express from 'express';
import { processRequest } from 'zod-express-middleware';
import { processRequest } from 'zod-express';

// Managers
import * as accountMan from '../managers/account';
import * as permsMan from '../managers/permissions';

// Validation
import * as AccountValidators from '../engines/validation/models/account';
import { validationErrorHandler } from '../engines/validation/express';

// Utils
import { ensureAuthenticated, errorHandler } from './utils';

// Logger
import logging from '@strata-js/util-logging';

const logger = logging.getLogger(module.filename);

//----------------------------------------------------------------------------------------------------------------------
Expand All @@ -25,41 +27,62 @@ const router = express.Router();

//----------------------------------------------------------------------------------------------------------------------

router.get('/', processRequest({ query: AccountValidators.AccountFilter }), async(req, resp) =>
{
resp.json((await accountMan.list(req.query)).map((accountObj) =>
{
const { permissions, settings, groups, ...restAccount } = accountObj;
return restAccount;
}));
});

router.get('/:accountID', processRequest({ params: AccountValidators.UpdateParams }), async(req, resp) =>
{
const user = req.user;
const account = await accountMan.get(req.params.accountID);

const sameOrAdmin = user && (user.id === req.params.accountID || permsMan.hasPerm(user, `Accounts/canViewDetails`));

if(req.isAuthenticated() && sameOrAdmin)
router.get(
'/',
processRequest({ query: AccountValidators.AccountFilter }, { passErrorToNext: true }),
async (req, resp) =>
{
resp.json(account);
resp.json((await accountMan.list(req.query)).map((accountObj) =>
{
const {
permissions,
settings,
groups,
...restAccount
} = accountObj;
return restAccount;
}));
}
else
);

router.get(
'/:accountID',
processRequest({ params: AccountValidators.UpdateParams }, { passErrorToNext: true }),
async (req, resp) =>
{
const { permissions, groups, settings, ...restAccount } = account;
resp.json(restAccount);
const user = req.user;
const account = await accountMan.get(req.params.accountID);

const sameOrAdmin = user && (user.id === req.params.accountID || permsMan.hasPerm(
user,
`Accounts/canViewDetails`
));

if(req.isAuthenticated() && sameOrAdmin)
{
resp.json(account);
}
else
{
const {
permissions,
groups,
settings,
...restAccount
} = account;
resp.json(restAccount);
}
}
});
);

router.patch(
'/:accountID',
ensureAuthenticated,
processRequest({
params: AccountValidators.UpdateParams,
body: AccountValidators.Account.partial({ id: true })
}),
async(req, resp) =>
}, { passErrorToNext: true }),
async (req, resp) =>
{
// Update the account
const newAccount = await accountMan.update(req.params.accountID, req.body);
Expand All @@ -71,6 +94,7 @@ router.patch(
// Error Handling
//----------------------------------------------------------------------------------------------------------------------

router.use(validationErrorHandler);
router.use(errorHandler(logger));

//----------------------------------------------------------------------------------------------------------------------
Expand Down

0 comments on commit c0e3a16

Please sign in to comment.