From 6dd47859dfad9112f8ddf43e37578bd02e163dba Mon Sep 17 00:00:00 2001 From: Benny Neugebauer Date: Mon, 31 Jul 2023 16:16:03 +0100 Subject: [PATCH] refactor(withdraw): Validate responses with Zod (#875) --- src/withdraw/WithdrawAPI.test.ts | 6 ++- src/withdraw/WithdrawAPI.ts | 77 +++++++++++++++++++------------- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/src/withdraw/WithdrawAPI.test.ts b/src/withdraw/WithdrawAPI.test.ts index 4647ed45..28ce2d87 100644 --- a/src/withdraw/WithdrawAPI.test.ts +++ b/src/withdraw/WithdrawAPI.test.ts @@ -193,7 +193,11 @@ describe('WithdrawAPI', () => { ); const paymentMethods = await global.client.rest.withdraw.getPaymentMethods(); - expect(paymentMethods[0].limits.instant_buy[0].period_in_days).toBe(7); + if ('instant_buy' in paymentMethods[0].limits && paymentMethods[0].limits.instant_buy) { + expect(paymentMethods[0].limits.instant_buy[0].period_in_days).toBe(7); + } else { + throw new Error('No "instant_buy" limit found.'); + } }); }); }); diff --git a/src/withdraw/WithdrawAPI.ts b/src/withdraw/WithdrawAPI.ts index 8538bcee..134ee09e 100644 --- a/src/withdraw/WithdrawAPI.ts +++ b/src/withdraw/WithdrawAPI.ts @@ -1,3 +1,4 @@ +import {z} from 'zod'; import {AxiosInstance} from 'axios'; export interface CryptoWithdrawal { @@ -35,36 +36,52 @@ export interface WithdrawalFeeEstimate { fee: string; } -export interface PaymentMethodLimit { - period_in_days: number; - remaining: { - amount: string; - currency: string; - }; - total: { - amount: string; - currency: string; - }; -} +export const PaymentMethodLimitSchema = z.object({ + period_in_days: z.number(), + remaining: z.object({ + amount: z.string(), + currency: z.string(), + }), + total: z.object({ + amount: z.string(), + currency: z.string(), + }), +}); -export interface PaymentMethod { - allow_buy: boolean; - allow_deposit: boolean; - allow_sell: boolean; - allow_withdraw: boolean; - currency: string; - id: string; - limits: { - buy: PaymentMethodLimit[]; - deposit: PaymentMethodLimit[]; - instant_buy: PaymentMethodLimit[]; - sell: PaymentMethodLimit[]; - }; - name: string; - primary_buy: boolean; - primary_sell: boolean; - type: string; -} +export type PaymentMethodLimit = z.infer; + +export const PaymentMethodSchema = z.object({ + allow_buy: z.boolean(), + allow_deposit: z.boolean(), + allow_sell: z.boolean(), + allow_withdraw: z.boolean(), + created_at: z.string().nullable().or(z.undefined()), + currency: z.string().nullable().or(z.undefined()), + fiat_account: z + .object({ + id: z.string(), + resource: z.string(), + }) + .optional(), + id: z.string(), + limits: z + .object({ + buy: z.array(PaymentMethodLimitSchema).optional(), + deposit: z.array(PaymentMethodLimitSchema).optional(), + instant_buy: z.array(PaymentMethodLimitSchema).optional(), + sell: z.array(PaymentMethodLimitSchema).optional(), + }) + .or(z.object({})), + name: z.string(), + primary_buy: z.boolean(), + primary_sell: z.boolean(), + resource: z.string().nullable().or(z.undefined()), + resource_path: z.string().nullable().or(z.undefined()), + type: z.string(), + updated_at: z.string().nullable().or(z.undefined()), +}); + +export type PaymentMethod = z.infer; export class WithdrawAPI { static readonly URL = { @@ -183,6 +200,6 @@ export class WithdrawAPI { async getPaymentMethods(): Promise { const resource = WithdrawAPI.URL.LIST_PAYMENT_METHODS; const response = await this.apiClient.get(resource); - return response.data; + return z.array(PaymentMethodSchema).parse(response.data); } }