cal.com
cal.com copied to clipboard
[CAL-3977] Zod Errors in any /payments and /payments/[id] API Endpoints
Issue Summary
The /payments API and /payments/[id] endpoints are returning zod errors, making it impossible to retrieve the payment UID necessary for constructing abandoned cart recovery links.
Steps to Reproduce
- Make a request to the
/paymentsAPI. - Observe the response, which returns zod errors.
- Make a request to the
/payments/[id]endpoint. - Observe the response, which also returns zod errors.
This issue is considered a bug because the API should return valid data without errors, enabling the retrieval of the payment UID.
Actual Results
- The
/paymentsAPI and/payments/[id]endpoints return zod errors, preventing the retrieval of payment UIDs.
Expected Results
- The
/paymentsAPI and/payments/[id]endpoints should return valid responses, including the payment UID, without any zod errors.
Technical details
Evidence
- This bug was tested by making API requests to
/paymentsand/payments/[id]. Both endpoints returned zod errors.
By following the steps above, you can replicate the issue and observe the unexpected zod errors. The expected outcome is that the API should return the required payment UID without any errors
To resolve the Zod errors encountered when making requests to the /payments and /payments/[id] API endpoints, ensure that the query parameters and the response data conform to the expected schema definitions. Here is a step-by-step approach to troubleshoot and resolve the Zod errors:
-
Validate Query Parameters: Ensure that the query parameters passed to the API endpoints match the expected schema. The
schemaQueryIdParseIntschema is used to validate and parse theidparameter. -
Validate Response Data: Ensure that the response data from the database matches the
schemaPaymentPublicschema. This schema is used to validate the payment data before sending it in the response. Note that theschemaPaymentPublicschema omits theexternalIdfield from the payment data. -
Error Handling: Properly handle and log errors to understand the cause of the Zod validation failures. Implement a Zod exception filter to catch and log detailed error information.
Here is the relevant code snippet with comments to help you understand the validation process:
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "~/lib/helpers/withMiddleware";
import type { PaymentResponse } from "~/lib/types";
import { schemaPaymentPublic } from "~/lib/validations/payment";
import {
schemaQueryIdParseInt,
withValidQueryIdTransformParseInt,
} from "~/lib/validations/shared/queryIdTransformParseInt";
/**
* @swagger
* /payments/{id}:
* get:
* summary: Find a payment
* parameters:
* - in: query
* name: apiKey
* required: true
* schema:
* type: string
* description: Your API key
* - in: path
* name: id
* schema:
* type: integer
* required: true
* description: ID of the payment to get
* tags:
* - payments
* responses:
* 200:
* description: OK
* 401:
* description: Authorization information is missing or invalid.
* 404:
* description: Payment was not found
*/
export async function paymentById(
{ method, query, userId }: NextApiRequest,
res: NextApiResponse<PaymentResponse>
) {
// Validate and parse the query parameters
const safeQuery = schemaQueryIdParseInt.safeParse(query);
if (safeQuery.success && method === "GET") {
const userWithBookings = await prisma.user.findUnique({
where: { id: userId },
include: { bookings: true },
});
// Fetch and validate the payment data
await prisma.payment
.findUnique({ where: { id: safeQuery.data.id } })
.then((data) => schemaPaymentPublic.parse(data))
.then((payment) => {
// Check if the user is authorized to view the payment
if (!userWithBookings?.bookings.map((b) => b.id).includes(payment.bookingId)) {
res.status(401).json({ message: "Unauthorized" });
} else {
res.status(200).json({ payment });
}
})
.catch((error: Error) =>
res.status(404).json({
message: `Payment with id: ${safeQuery.data.id} not found`,
error,
})
);
} else {
// Handle invalid query parameters
res.status(400).json({ message: "Invalid query parameters" });
}
}
export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(paymentById));
Additionally, implement a Zod exception filter to catch and log detailed error information:
import type { ArgumentsHost, ExceptionFilter } from "@nestjs/common";
import { Catch, HttpStatus, Logger } from "@nestjs/common";
import { Request } from "express";
import { ZodError } from "zod";
import { BAD_REQUEST, ERROR_STATUS } from "@calcom/platform-constants";
import { Response } from "@calcom/platform-types";
@Catch(ZodError)
export class ZodExceptionFilter implements ExceptionFilter {
private readonly logger = new Logger("ZodExceptionFilter");
catch(error: ZodError, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const requestId = request.headers["X-Request-Id"];
this.logger.error(`ZodError: ${error.message}`, {
error,
body: request.body,
headers: request.headers,
url: request.url,
method: request.method,
requestId,
});
response.status(HttpStatus.BAD_REQUEST).json({
status: ERROR_STATUS,
timestamp: new Date().toISOString(),
path: request.url,
error: {
code: BAD_REQUEST,
message: error.issues.reduce(
(acc, issue) => `${issue.path.join(".")} - ${issue.message}, ${acc}`,
""
),
},
});
}
}
Ensure that the id parameter in the query is an integer and that the payment data returned from the database matches the schemaPaymentPublic schema, which omits the externalId field. If there are any discrepancies, adjust the input data or the schema definitions accordingly [1][2][3].
To continue talking to Dosu, mention @dosu.
Second this! Happens on both endpoints for me as well. It seems like an issue/error occurs when running the parse function of _paymentModel in @calcom/prisma/zod. because of data type differences. Critical issue for us since we can't retrieve payment UID for abandoned carts payment links and other payment details for internal reference.
@PeerRich Duplicate of https://github.com/calcom/cal.com/issues/10665 which has been closed
cc @keithwillcode
cc @JDP-Neo