Merge branch 'mayank' of http://git.wdipl.com/Mayank.Mishra/MinglarBackendNestJS into paritosh
This commit is contained in:
126
src/common/utils/helper/parseMultipartFormData.ts
Normal file
126
src/common/utils/helper/parseMultipartFormData.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import ApiError from './ApiError';
|
||||
|
||||
interface ParsedFormData {
|
||||
fields: Record<string, string>;
|
||||
files: Array<{
|
||||
fieldName: string;
|
||||
fileName: string;
|
||||
contentType: string;
|
||||
data: Buffer;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse multipart/form-data from Lambda event
|
||||
* Supports both base64 encoded and binary body
|
||||
*/
|
||||
export function parseMultipartFormData(
|
||||
eventBody: string | null,
|
||||
contentType: string | undefined,
|
||||
isBase64Encoded: boolean = false
|
||||
): ParsedFormData {
|
||||
if (!eventBody) {
|
||||
throw new ApiError(400, 'Request body is required');
|
||||
}
|
||||
|
||||
if (!contentType || !contentType.includes('multipart/form-data')) {
|
||||
throw new ApiError(400, 'Content-Type must be multipart/form-data');
|
||||
}
|
||||
|
||||
// Extract boundary from Content-Type header
|
||||
const boundaryMatch = contentType.match(/boundary=([^;]+)/);
|
||||
if (!boundaryMatch) {
|
||||
throw new ApiError(400, 'Invalid multipart boundary');
|
||||
}
|
||||
const boundary = boundaryMatch[1].trim();
|
||||
|
||||
// Decode base64 body if needed (API Gateway sends base64 encoded for binary media types)
|
||||
let bodyBuffer: Buffer;
|
||||
try {
|
||||
if (isBase64Encoded) {
|
||||
bodyBuffer = Buffer.from(eventBody, 'base64');
|
||||
} else {
|
||||
// Try to detect if it's base64
|
||||
if (eventBody.match(/^[A-Za-z0-9+/=]+$/)) {
|
||||
bodyBuffer = Buffer.from(eventBody, 'base64');
|
||||
} else {
|
||||
bodyBuffer = Buffer.from(eventBody, 'binary');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
throw new ApiError(400, 'Invalid request body encoding');
|
||||
}
|
||||
|
||||
// Split by boundary
|
||||
const parts = bodyBuffer.toString('binary').split(`--${boundary}`);
|
||||
|
||||
const fields: Record<string, string> = {};
|
||||
const files: ParsedFormData['files'] = [];
|
||||
|
||||
for (const part of parts) {
|
||||
if (!part || part.trim() === '' || part.trim() === '--') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Split headers and body
|
||||
const [headers, ...bodyParts] = part.split('\r\n\r\n');
|
||||
if (!headers || bodyParts.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const body = bodyParts.join('\r\n\r\n').trim();
|
||||
if (!body) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse Content-Disposition header
|
||||
const contentDispositionMatch = headers.match(/Content-Disposition:\s*form-data;\s*name="([^"]+)"/);
|
||||
if (!contentDispositionMatch) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const fieldName = contentDispositionMatch[1];
|
||||
|
||||
// Check if it's a file
|
||||
const filenameMatch = headers.match(/filename="([^"]+)"/);
|
||||
const contentTypeMatch = headers.match(/Content-Type:\s*([^\r\n]+)/);
|
||||
|
||||
if (filenameMatch) {
|
||||
// It's a file
|
||||
const fileName = filenameMatch[1];
|
||||
const fileContentType = contentTypeMatch ? contentTypeMatch[1].trim() : 'application/octet-stream';
|
||||
|
||||
// Convert body to buffer (remove trailing boundary markers)
|
||||
const fileData = Buffer.from(body.replace(/\r\n--$/, ''), 'binary');
|
||||
|
||||
files.push({
|
||||
fieldName,
|
||||
fileName,
|
||||
contentType: fileContentType,
|
||||
data: fileData,
|
||||
});
|
||||
} else {
|
||||
// It's a regular field
|
||||
fields[fieldName] = body.replace(/\r\n--$/, '').trim();
|
||||
}
|
||||
}
|
||||
|
||||
return { fields, files };
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse JSON field from form data
|
||||
*/
|
||||
export function parseJsonField(fields: Record<string, string>, fieldName: string): any {
|
||||
const value = fields[fieldName];
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (error) {
|
||||
throw new ApiError(400, `Invalid JSON in field: ${fieldName}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ import { z } from "zod";
|
||||
|
||||
// Allowed document types (must match your DocumentType master table IDs)
|
||||
export const REQUIRED_DOC_TYPES = {
|
||||
PAN: 1,
|
||||
GST: 2,
|
||||
GST: 1,
|
||||
PAN: 2,
|
||||
REGISTRATION: 3,
|
||||
AADHAAR: 4,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user