Skip to content

Commit

Permalink
refactor(validation): replace ajv with zod (#73)
Browse files Browse the repository at this point in the history
refactors all the remaining AJV schema validation

to review more easily, you can review 1 commit at a time. each commit
should be reviewable by itself

cc
https://linear.app/valora/issue/ACT-528/use-zod-instead-of-ajv-in-fiatconnect-api-starter-mock-provider
  • Loading branch information
cajubelt authored Nov 16, 2022
1 parent 3f0c4d2 commit edfdc97
Show file tree
Hide file tree
Showing 17 changed files with 35 additions and 386 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
"@typescript-eslint/eslint-plugin": "^5.40.1",
"@valora/eslint-config-typescript": "^0.0.1",
"@valora/prettier-config": "^0.0.1",
"ajv": "^8.11.0",
"dotenv": "^16.0.3",
"eslint": "^8.25.0",
"eslint-plugin-import": "^2.26.0",
Expand Down
11 changes: 7 additions & 4 deletions src/routes/accounts.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import express from 'express'
import { asyncRoute } from './async-route'
import { validateSchema, validateZodSchema } from '../schema/'
import { validateZodSchema } from '../schema/'
import {
DeleteFiatAccountRequestParams,
NotImplementedError,
PostFiatAccountRequestBody,
} from '../types'
import { siweAuthMiddleware } from '../middleware/authenticate'
import { postFiatAccountRequestBodySchema } from '@fiatconnect/fiatconnect-types'
import {
deleteFiatAccountRequestParamsSchema,
postFiatAccountRequestBodySchema,
} from '@fiatconnect/fiatconnect-types'

export function accountsRouter({
clientAuthMiddleware,
Expand All @@ -33,9 +36,9 @@ export function accountsRouter({
_res: express.Response,
next: express.NextFunction,
) => {
req.params = validateSchema<DeleteFiatAccountRequestParams>(
req.params = validateZodSchema(
req.params,
'DeleteFiatAccountRequestParamsSchema',
deleteFiatAccountRequestParamsSchema,
)
next()
}
Expand Down
8 changes: 3 additions & 5 deletions src/routes/auth.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import express from 'express'
import { ErrorTypes, SiweMessage } from 'siwe'
import { validateSchema } from '../schema'
import { validateZodSchema } from '../schema'
import {
AuthRequestBody,
FiatConnectError,
InvalidSiweParamsError,
NotImplementedError,
} from '../types'
import { asyncRoute } from './async-route'
import { authRequestBodySchema } from '@fiatconnect/fiatconnect-types'

const MAX_EXPIRATION_TIME_MS = 4 * 60 * 60 * 1000 // 4 hours
const VERSION = '1'
Expand Down Expand Up @@ -73,10 +74,7 @@ export function authRouter({ chainId }: { chainId: number }): express.Router {
_res: express.Response,
next: express.NextFunction,
) => {
req.body = validateSchema<AuthRequestBody>(
req.body,
'AuthRequestBodySchema',
)
req.body = validateZodSchema(req.body, authRequestBodySchema)
next()
}

Expand Down
23 changes: 14 additions & 9 deletions src/routes/kyc.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import express from 'express'
import { asyncRoute } from './async-route'
import { validateSchema } from '../schema/'
import { validateZodSchema } from '../schema/'
import {
KycRequestParams,
KycSchemas,
NotImplementedError,
SupportedKycSchemas,
} from '../types'
import { siweAuthMiddleware } from '../middleware/authenticate'
import {
kycRequestParamsSchema,
KycSchema,
personalDataAndDocumentsKycSchema,
} from '@fiatconnect/fiatconnect-types'
import { AnyZodObject } from 'zod'

const kycSchemaToZodSchema: { [kycSchema in KycSchema]: AnyZodObject } = {
// if a KYC schema is missing, that should be evident at compile-time, as long as fiatconnect-types is up to date
[KycSchema.PersonalDataAndDocuments]: personalDataAndDocumentsKycSchema,
}

export function kycRouter({
clientAuthMiddleware,
Expand All @@ -24,10 +35,7 @@ export function kycRouter({
_res: express.Response,
next: express.NextFunction,
) => {
req.params = validateSchema<KycRequestParams>(
req.params,
'KycRequestParamsSchema',
)
req.params = validateZodSchema(req.params, kycRequestParamsSchema)
next()
}

Expand All @@ -44,10 +52,7 @@ export function kycRouter({
_res: express.Response,
) => {
// Delegate to type-specific handlers after validation provides type guards
validateSchema<KycSchemas[typeof req.params.kycSchema]>(
req.body,
`${req.params.kycSchema}KycSchema`,
)
validateZodSchema(req.body, kycSchemaToZodSchema[req.params.kycSchema])

throw new NotImplementedError('POST /kyc/:kycSchema not implemented')
},
Expand Down
8 changes: 3 additions & 5 deletions src/routes/quote.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import express from 'express'
import { asyncRoute } from './async-route'
import { validateSchema } from '../schema/'
import { validateZodSchema } from '../schema/'
import { QuoteRequestBody, NotImplementedError } from '../types'
import { quoteRequestBodySchema } from '@fiatconnect/fiatconnect-types'

export function quoteRouter({
clientAuthMiddleware,
Expand All @@ -18,10 +19,7 @@ export function quoteRouter({
_res: express.Response,
next: express.NextFunction,
) => {
req.body = validateSchema<QuoteRequestBody>(
req.body,
'QuoteRequestBodySchema',
)
req.body = validateZodSchema(req.body, quoteRequestBodySchema)
next()
},
)
Expand Down
15 changes: 8 additions & 7 deletions src/routes/transfer.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import express from 'express'
import { asyncRoute } from './async-route'
import { validateSchema } from '../schema/'
import { validateZodSchema } from '../schema/'
import {
TransferRequestBody,
TransferStatusRequestParams,
NotImplementedError,
} from '../types'
import { siweAuthMiddleware } from '../middleware/authenticate'
import {
transferRequestBodySchema,
transferStatusRequestParamsSchema,
} from '@fiatconnect/fiatconnect-types'

export function transferRouter({
clientAuthMiddleware,
Expand All @@ -23,10 +27,7 @@ export function transferRouter({
_res: express.Response,
next: express.NextFunction,
) => {
req.body = validateSchema<TransferRequestBody>(
req.body,
'TransferRequestBodySchema',
)
req.body = validateZodSchema(req.body, transferRequestBodySchema)
next()
}

Expand All @@ -35,9 +36,9 @@ export function transferRouter({
_res: express.Response,
next: express.NextFunction,
) => {
req.params = validateSchema<TransferStatusRequestParams>(
req.params = validateZodSchema(
req.params,
'TransferStatusRequestParamsSchema',
transferStatusRequestParamsSchema,
)
next()
}
Expand Down
38 changes: 0 additions & 38 deletions src/schema/account-number.ts

This file was deleted.

16 changes: 0 additions & 16 deletions src/schema/auth-request-body.ts

This file was deleted.

14 changes: 0 additions & 14 deletions src/schema/delete-fiat-account-request-params.ts

This file was deleted.

29 changes: 0 additions & 29 deletions src/schema/dunia-wallet.ts

This file was deleted.

37 changes: 0 additions & 37 deletions src/schema/index.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,8 @@
import Ajv from 'ajv'
import { ValidationError } from '../types'

import { quoteRequestBodySchema } from './quote-request-body'
import { kycRequestParamsSchema } from './kyc-request-params'
import { personalDataAndDocumentsKycSchema } from './personal-data-and-documents-kyc'
import { deleteFiatAccountRequestParamsSchema } from './delete-fiat-account-request-params'
import { transferRequestBodySchema } from './transfer-request-body'
import { transferStatusRequestParamsSchema } from './transfer-status-request-params'
import { authRequestBodySchema } from './auth-request-body'
import { z, ZodError } from 'zod'
import { ZodType } from 'zod/lib/types'

const ajv = new Ajv({
schemas: [
quoteRequestBodySchema,
kycRequestParamsSchema,
personalDataAndDocumentsKycSchema,
deleteFiatAccountRequestParamsSchema,
transferRequestBodySchema,
transferStatusRequestParamsSchema,
authRequestBodySchema,
],
})

/**
* Validate AJV schema
*
* @deprecated - prefer validateZodSchema (more re-usable with fiatconnect-types)
*
* @param data
* @param schema
*/
export function validateSchema<T>(data: any, schema: string): T {
if (ajv.validate(schema, data)) return data

throw new ValidationError(
`Error while validating schema: invalid ${schema}`,
ajv.errors,
)
}

/**
* Validate zod schema
*
Expand Down
14 changes: 0 additions & 14 deletions src/schema/kyc-request-params.ts

This file was deleted.

49 changes: 0 additions & 49 deletions src/schema/mobile-money.ts

This file was deleted.

Loading

0 comments on commit edfdc97

Please sign in to comment.