Enhance API services with validation and error handling improvements
- Integrated Zod validation schemas across various API routes to ensure input integrity and improve error handling. - Updated `mapping-service`, `orchestrator`, `packet-service`, and `webhook-service` to utilize validation middleware for request parameters and bodies. - Improved error handling in webhook management, packet generation, and compliance routes to provide clearer feedback on request failures. - Added new validation schemas for various endpoints, enhancing overall API robustness and maintainability. - Updated dependencies in `package.json` to include the new validation library.
This commit is contained in:
@@ -1,11 +1,18 @@
|
||||
import { Router } from 'express';
|
||||
import { z } from 'zod';
|
||||
import { requireRole } from '../middleware/rbac';
|
||||
import { validateBody, validateParams } from '@emoney/validation/middleware';
|
||||
import { bridgeLock, bridgeUnlock, getBridgeLock, getBridgeCorridors } from '../controllers/bridge';
|
||||
import { bridgeLockSchema, bridgeUnlockSchema } from '@emoney/validation/validators';
|
||||
|
||||
export const bridgeRouter = Router();
|
||||
|
||||
bridgeRouter.post('/lock', bridgeLock);
|
||||
bridgeRouter.post('/unlock', requireRole('BRIDGE_OPERATOR'), bridgeUnlock);
|
||||
bridgeRouter.get('/locks/:lockId', getBridgeLock);
|
||||
const lockIdParam = z.object({
|
||||
lockId: z.string().regex(/^[a-fA-F0-9]{64}$/, 'Invalid lock ID'),
|
||||
});
|
||||
|
||||
bridgeRouter.post('/lock', validateBody(bridgeLockSchema), bridgeLock);
|
||||
bridgeRouter.post('/unlock', requireRole('BRIDGE_OPERATOR'), validateBody(bridgeUnlockSchema), bridgeUnlock);
|
||||
bridgeRouter.get('/locks/:lockId', validateParams(lockIdParam), getBridgeLock);
|
||||
bridgeRouter.get('/corridors', getBridgeCorridors);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Router } from 'express';
|
||||
import { z } from 'zod';
|
||||
import { requireRole } from '../middleware/rbac';
|
||||
import { validateBody, validateParams } from '@emoney/validation/middleware';
|
||||
import {
|
||||
getComplianceProfile,
|
||||
setCompliance,
|
||||
@@ -12,20 +14,82 @@ import {
|
||||
setWalletTier,
|
||||
setWalletJurisdictionHash,
|
||||
} from '../controllers/compliance';
|
||||
import {
|
||||
setComplianceSchema,
|
||||
setFrozenSchema,
|
||||
setTierSchema,
|
||||
setJurisdictionHashSchema,
|
||||
} from '@emoney/validation/validators';
|
||||
|
||||
export const complianceRouter = Router();
|
||||
|
||||
const accountRefIdParam = z.object({
|
||||
accountRefId: z.string().regex(/^0x[a-fA-F0-9]{64}$/, 'Invalid account reference ID'),
|
||||
});
|
||||
|
||||
const walletRefIdParam = z.object({
|
||||
walletRefId: z.string().regex(/^0x[a-fA-F0-9]{64}$/, 'Invalid wallet reference ID'),
|
||||
});
|
||||
|
||||
// Account compliance
|
||||
complianceRouter.put('/accounts/:accountRefId', requireRole('COMPLIANCE'), setCompliance);
|
||||
complianceRouter.get('/accounts/:accountRefId', getComplianceProfile);
|
||||
complianceRouter.put('/accounts/:accountRefId/freeze', requireRole('COMPLIANCE'), setFrozen);
|
||||
complianceRouter.put('/accounts/:accountRefId/tier', requireRole('COMPLIANCE'), setTier);
|
||||
complianceRouter.put('/accounts/:accountRefId/jurisdiction', requireRole('COMPLIANCE'), setJurisdictionHash);
|
||||
complianceRouter.put(
|
||||
'/accounts/:accountRefId',
|
||||
requireRole('COMPLIANCE'),
|
||||
validateParams(accountRefIdParam),
|
||||
validateBody(setComplianceSchema),
|
||||
setCompliance
|
||||
);
|
||||
complianceRouter.get('/accounts/:accountRefId', validateParams(accountRefIdParam), getComplianceProfile);
|
||||
complianceRouter.put(
|
||||
'/accounts/:accountRefId/freeze',
|
||||
requireRole('COMPLIANCE'),
|
||||
validateParams(accountRefIdParam),
|
||||
validateBody(setFrozenSchema),
|
||||
setFrozen
|
||||
);
|
||||
complianceRouter.put(
|
||||
'/accounts/:accountRefId/tier',
|
||||
requireRole('COMPLIANCE'),
|
||||
validateParams(accountRefIdParam),
|
||||
validateBody(setTierSchema),
|
||||
setTier
|
||||
);
|
||||
complianceRouter.put(
|
||||
'/accounts/:accountRefId/jurisdiction',
|
||||
requireRole('COMPLIANCE'),
|
||||
validateParams(accountRefIdParam),
|
||||
validateBody(setJurisdictionHashSchema),
|
||||
setJurisdictionHash
|
||||
);
|
||||
|
||||
// Wallet compliance
|
||||
complianceRouter.put('/wallets/:walletRefId', requireRole('COMPLIANCE'), setWalletCompliance);
|
||||
complianceRouter.get('/wallets/:walletRefId', getWalletComplianceProfile);
|
||||
complianceRouter.put('/wallets/:walletRefId/freeze', requireRole('COMPLIANCE'), setWalletFrozen);
|
||||
complianceRouter.put('/wallets/:walletRefId/tier', requireRole('COMPLIANCE'), setWalletTier);
|
||||
complianceRouter.put('/wallets/:walletRefId/jurisdiction', requireRole('COMPLIANCE'), setWalletJurisdictionHash);
|
||||
complianceRouter.put(
|
||||
'/wallets/:walletRefId',
|
||||
requireRole('COMPLIANCE'),
|
||||
validateParams(walletRefIdParam),
|
||||
validateBody(setComplianceSchema),
|
||||
setWalletCompliance
|
||||
);
|
||||
complianceRouter.get('/wallets/:walletRefId', validateParams(walletRefIdParam), getWalletComplianceProfile);
|
||||
complianceRouter.put(
|
||||
'/wallets/:walletRefId/freeze',
|
||||
requireRole('COMPLIANCE'),
|
||||
validateParams(walletRefIdParam),
|
||||
validateBody(setFrozenSchema),
|
||||
setWalletFrozen
|
||||
);
|
||||
complianceRouter.put(
|
||||
'/wallets/:walletRefId/tier',
|
||||
requireRole('COMPLIANCE'),
|
||||
validateParams(walletRefIdParam),
|
||||
validateBody(setTierSchema),
|
||||
setWalletTier
|
||||
);
|
||||
complianceRouter.put(
|
||||
'/wallets/:walletRefId/jurisdiction',
|
||||
requireRole('COMPLIANCE'),
|
||||
validateParams(walletRefIdParam),
|
||||
validateBody(setJurisdictionHashSchema),
|
||||
setWalletJurisdictionHash
|
||||
);
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import { Router } from 'express';
|
||||
import { requireRole } from '../middleware/rbac';
|
||||
import { validateBody } from '@emoney/validation/middleware';
|
||||
import { submitInboundMessage, submitOutboundMessage } from '../controllers/iso';
|
||||
import {
|
||||
submitInboundMessageSchema,
|
||||
submitOutboundMessageSchema,
|
||||
} from '@emoney/validation/validators';
|
||||
|
||||
export const isoRouter = Router();
|
||||
|
||||
isoRouter.post('/inbound', submitInboundMessage); // mTLS or OAuth2
|
||||
isoRouter.post('/outbound', submitOutboundMessage);
|
||||
isoRouter.post('/inbound', validateBody(submitInboundMessageSchema), submitInboundMessage); // mTLS or OAuth2
|
||||
isoRouter.post('/outbound', validateBody(submitOutboundMessageSchema), submitOutboundMessage);
|
||||
|
||||
|
||||
@@ -1,14 +1,30 @@
|
||||
import { Router } from 'express';
|
||||
import { z } from 'zod';
|
||||
import { requireRole } from '../middleware/rbac';
|
||||
import { validateBody, validateQuery, validateParams } from '@emoney/validation/middleware';
|
||||
import { placeLien, listLiens, getLien, reduceLien, releaseLien, getAccountLiens, getEncumbrance } from '../controllers/liens';
|
||||
import {
|
||||
placeLienSchema,
|
||||
reduceLienSchema,
|
||||
listLiensQuerySchema,
|
||||
getEncumbranceQuerySchema,
|
||||
} from '@emoney/validation/validators';
|
||||
|
||||
export const liensRouter = Router();
|
||||
|
||||
liensRouter.post('/', requireRole('DEBT_AUTHORITY'), placeLien);
|
||||
liensRouter.get('/', listLiens);
|
||||
liensRouter.get('/:lienId', getLien);
|
||||
liensRouter.patch('/:lienId', requireRole('DEBT_AUTHORITY'), reduceLien);
|
||||
liensRouter.delete('/:lienId', requireRole('DEBT_AUTHORITY'), releaseLien);
|
||||
liensRouter.get('/accounts/:accountRefId/liens', getAccountLiens);
|
||||
liensRouter.get('/accounts/:accountRefId/encumbrance', getEncumbrance);
|
||||
const lienIdParam = z.object({
|
||||
lienId: z.string().regex(/^[0-9]+$/, 'Invalid lien ID'),
|
||||
});
|
||||
|
||||
const accountRefIdParam = z.object({
|
||||
accountRefId: z.string().regex(/^0x[a-fA-F0-9]{64}$/, 'Invalid account reference ID'),
|
||||
});
|
||||
|
||||
liensRouter.post('/', requireRole('DEBT_AUTHORITY'), validateBody(placeLienSchema), placeLien);
|
||||
liensRouter.get('/', validateQuery(listLiensQuerySchema), listLiens);
|
||||
liensRouter.get('/:lienId', validateParams(lienIdParam), getLien);
|
||||
liensRouter.patch('/:lienId', requireRole('DEBT_AUTHORITY'), validateParams(lienIdParam), validateBody(reduceLienSchema), reduceLien);
|
||||
liensRouter.delete('/:lienId', requireRole('DEBT_AUTHORITY'), validateParams(lienIdParam), releaseLien);
|
||||
liensRouter.get('/accounts/:accountRefId/liens', validateParams(accountRefIdParam), getAccountLiens);
|
||||
liensRouter.get('/accounts/:accountRefId/encumbrance', validateParams(accountRefIdParam), validateQuery(getEncumbranceQuerySchema), getEncumbrance);
|
||||
|
||||
|
||||
@@ -1,12 +1,32 @@
|
||||
import { Router } from 'express';
|
||||
import { z } from 'zod';
|
||||
import { validateBody, validateParams } from '@emoney/validation/middleware';
|
||||
import { linkAccountWallet, unlinkAccountWallet, getAccountWallets, getWalletAccounts, connectProvider, getProviderStatus } from '../controllers/mappings';
|
||||
import {
|
||||
linkAccountWalletSchema,
|
||||
unlinkAccountWalletSchema,
|
||||
connectProviderSchema,
|
||||
} from '@emoney/validation/validators';
|
||||
|
||||
export const mappingsRouter = Router();
|
||||
|
||||
mappingsRouter.post('/account-wallet/link', linkAccountWallet);
|
||||
mappingsRouter.post('/account-wallet/unlink', unlinkAccountWallet);
|
||||
mappingsRouter.get('/accounts/:accountRefId/wallets', getAccountWallets);
|
||||
mappingsRouter.get('/wallets/:walletRefId/accounts', getWalletAccounts);
|
||||
mappingsRouter.post('/providers/:provider/connect', connectProvider);
|
||||
mappingsRouter.get('/providers/:provider/connections/:connectionId/status', getProviderStatus);
|
||||
const accountRefIdParam = z.object({
|
||||
accountRefId: z.string().regex(/^0x[a-fA-F0-9]{64}$/, 'Invalid account reference ID'),
|
||||
});
|
||||
|
||||
const walletRefIdParam = z.object({
|
||||
walletRefId: z.string().regex(/^0x[a-fA-F0-9]{64}$/, 'Invalid wallet reference ID'),
|
||||
});
|
||||
|
||||
const providerParams = z.object({
|
||||
provider: z.string().min(1, 'Provider is required'),
|
||||
connectionId: z.string().min(1, 'Connection ID is required'),
|
||||
});
|
||||
|
||||
mappingsRouter.post('/account-wallet/link', validateBody(linkAccountWalletSchema), linkAccountWallet);
|
||||
mappingsRouter.post('/account-wallet/unlink', validateBody(unlinkAccountWalletSchema), unlinkAccountWallet);
|
||||
mappingsRouter.get('/accounts/:accountRefId/wallets', validateParams(accountRefIdParam), getAccountWallets);
|
||||
mappingsRouter.get('/wallets/:walletRefId/accounts', validateParams(walletRefIdParam), getWalletAccounts);
|
||||
mappingsRouter.post('/providers/:provider/connect', validateParams(z.object({ provider: z.string().min(1) })), validateBody(connectProviderSchema), connectProvider);
|
||||
mappingsRouter.get('/providers/:provider/connections/:connectionId/status', validateParams(providerParams), getProviderStatus);
|
||||
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
import { Router } from 'express';
|
||||
import { z } from 'zod';
|
||||
import { validateBody, validateQuery, validateParams } from '@emoney/validation/middleware';
|
||||
import { generatePacket, listPackets, getPacket, downloadPacket, dispatchPacket, acknowledgePacket } from '../controllers/packets';
|
||||
import {
|
||||
generatePacketSchema,
|
||||
dispatchPacketSchema,
|
||||
acknowledgePacketSchema,
|
||||
listPacketsQuerySchema,
|
||||
} from '@emoney/validation/validators';
|
||||
|
||||
export const packetsRouter = Router();
|
||||
|
||||
packetsRouter.post('/', generatePacket);
|
||||
packetsRouter.get('/', listPackets);
|
||||
packetsRouter.get('/:packetId', getPacket);
|
||||
packetsRouter.get('/:packetId/download', downloadPacket);
|
||||
packetsRouter.post('/:packetId/dispatch', dispatchPacket);
|
||||
packetsRouter.post('/:packetId/ack', acknowledgePacket);
|
||||
const packetIdParam = z.object({
|
||||
packetId: z.string().regex(/^[a-fA-F0-9]{64}$/, 'Invalid packet ID'),
|
||||
});
|
||||
|
||||
packetsRouter.post('/', validateBody(generatePacketSchema), generatePacket);
|
||||
packetsRouter.get('/', validateQuery(listPacketsQuerySchema), listPackets);
|
||||
packetsRouter.get('/:packetId', validateParams(packetIdParam), getPacket);
|
||||
packetsRouter.get('/:packetId/download', validateParams(packetIdParam), downloadPacket);
|
||||
packetsRouter.post('/:packetId/dispatch', validateParams(packetIdParam), validateBody(dispatchPacketSchema), dispatchPacket);
|
||||
packetsRouter.post('/:packetId/ack', validateParams(packetIdParam), validateBody(acknowledgePacketSchema), acknowledgePacket);
|
||||
|
||||
|
||||
@@ -3,21 +3,36 @@
|
||||
*/
|
||||
|
||||
import { Router } from 'express';
|
||||
import { z } from 'zod';
|
||||
import { deployToken, listTokens, getToken, updateTokenPolicy } from '../controllers/tokens';
|
||||
import { mintTokens, burnTokens, clawbackTokens, forceTransferTokens } from '../controllers/tokens';
|
||||
import { requireRole } from '../middleware/rbac';
|
||||
import { validateBody, validateQuery, validateParams } from '@emoney/validation/middleware';
|
||||
import {
|
||||
deployTokenSchema,
|
||||
updatePolicySchema,
|
||||
mintRequestSchema,
|
||||
burnRequestSchema,
|
||||
clawbackRequestSchema,
|
||||
forceTransferRequestSchema,
|
||||
listTokensQuerySchema,
|
||||
} from '@emoney/validation/validators';
|
||||
|
||||
export const tokensRouter = Router();
|
||||
|
||||
const tokenCodeParam = z.object({
|
||||
code: z.string().regex(/^[A-Z0-9]{1,10}$/, 'Invalid token code'),
|
||||
});
|
||||
|
||||
// Token deployment and management
|
||||
tokensRouter.post('/', requireRole('TOKEN_DEPLOYER'), deployToken);
|
||||
tokensRouter.get('/', listTokens);
|
||||
tokensRouter.get('/:code', getToken);
|
||||
tokensRouter.patch('/:code/policy', requireRole('POLICY_OPERATOR'), updateTokenPolicy);
|
||||
tokensRouter.post('/', requireRole('TOKEN_DEPLOYER'), validateBody(deployTokenSchema), deployToken);
|
||||
tokensRouter.get('/', validateQuery(listTokensQuerySchema), listTokens);
|
||||
tokensRouter.get('/:code', validateParams(tokenCodeParam), getToken);
|
||||
tokensRouter.patch('/:code/policy', requireRole('POLICY_OPERATOR'), validateParams(tokenCodeParam), validateBody(updatePolicySchema), updateTokenPolicy);
|
||||
|
||||
// Token operations
|
||||
tokensRouter.post('/:code/mint', requireRole('ISSUER'), mintTokens);
|
||||
tokensRouter.post('/:code/burn', requireRole('ISSUER'), burnTokens);
|
||||
tokensRouter.post('/:code/clawback', requireRole('ENFORCEMENT'), clawbackTokens);
|
||||
tokensRouter.post('/:code/force-transfer', requireRole('ENFORCEMENT'), forceTransferTokens);
|
||||
tokensRouter.post('/:code/mint', requireRole('ISSUER'), validateParams(tokenCodeParam), validateBody(mintRequestSchema), mintTokens);
|
||||
tokensRouter.post('/:code/burn', requireRole('ISSUER'), validateParams(tokenCodeParam), validateBody(burnRequestSchema), burnTokens);
|
||||
tokensRouter.post('/:code/clawback', requireRole('ENFORCEMENT'), validateParams(tokenCodeParam), validateBody(clawbackRequestSchema), clawbackTokens);
|
||||
tokensRouter.post('/:code/force-transfer', requireRole('ENFORCEMENT'), validateParams(tokenCodeParam), validateBody(forceTransferRequestSchema), forceTransferTokens);
|
||||
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
import { Router } from 'express';
|
||||
import { z } from 'zod';
|
||||
import { requireRole } from '../middleware/rbac';
|
||||
import { validateBody, validateQuery, validateParams } from '@emoney/validation/middleware';
|
||||
import { listTriggers, getTrigger, validateAndLock, markSubmitted, confirmSettled, confirmRejected } from '../controllers/triggers';
|
||||
import {
|
||||
listTriggersQuerySchema,
|
||||
markSubmittedSchema,
|
||||
confirmRejectedSchema,
|
||||
} from '@emoney/validation/validators';
|
||||
|
||||
export const triggersRouter = Router();
|
||||
|
||||
triggersRouter.get('/', listTriggers);
|
||||
triggersRouter.get('/:triggerId', getTrigger);
|
||||
triggersRouter.post('/:triggerId/validate-and-lock', requireRole('POLICY_OPERATOR'), validateAndLock);
|
||||
triggersRouter.post('/:triggerId/mark-submitted', requireRole('POLICY_OPERATOR'), markSubmitted);
|
||||
triggersRouter.post('/:triggerId/confirm-settled', requireRole('POLICY_OPERATOR'), confirmSettled);
|
||||
triggersRouter.post('/:triggerId/confirm-rejected', requireRole('POLICY_OPERATOR'), confirmRejected);
|
||||
const triggerIdParam = z.object({
|
||||
triggerId: z.string().regex(/^[a-fA-F0-9]{64}$/, 'Invalid trigger ID'),
|
||||
});
|
||||
|
||||
triggersRouter.get('/', validateQuery(listTriggersQuerySchema), listTriggers);
|
||||
triggersRouter.get('/:triggerId', validateParams(triggerIdParam), getTrigger);
|
||||
triggersRouter.post('/:triggerId/validate-and-lock', requireRole('POLICY_OPERATOR'), validateParams(triggerIdParam), validateAndLock);
|
||||
triggersRouter.post('/:triggerId/mark-submitted', requireRole('POLICY_OPERATOR'), validateParams(triggerIdParam), validateBody(markSubmittedSchema), markSubmitted);
|
||||
triggersRouter.post('/:triggerId/confirm-settled', requireRole('POLICY_OPERATOR'), validateParams(triggerIdParam), confirmSettled);
|
||||
triggersRouter.post('/:triggerId/confirm-rejected', requireRole('POLICY_OPERATOR'), validateParams(triggerIdParam), validateBody(confirmRejectedSchema), confirmRejected);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user