Last active
January 5, 2024 07:43
-
-
Save thim81/70383609b724ebab54b256696d07d488 to your computer and use it in GitHub Desktop.
Prisma Simple Schema Validation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import path, {dirname} from "path"; | |
import {fileURLToPath} from "url"; | |
import prismaInternals from '@prisma/internals'; | |
const {getDMMF} = prismaInternals; | |
const __filename = fileURLToPath(import.meta.url); | |
const __dirname = dirname(__filename); | |
export const validateRequestPayload = async (modelName, requestBody) => { | |
try { | |
// Get Prisma DMMF | |
const dmmf = await getDMMF({ | |
datamodelPath: path.join(__dirname, '../../prisma/schema.prisma'), | |
}); | |
// Find the model schema by name | |
const modelSchema = dmmf.datamodel.models.find((model) => model.name === modelName); | |
if (!modelSchema) { | |
throw new Error(`Model ${modelName} not found in the schema.`); | |
} | |
// Array to store validation errors | |
const validationErrors = []; | |
// Filter out fields not present in the model schema | |
const validFields = Object.keys(requestBody).filter((fieldName) => | |
modelSchema.fields.some((field) => field.name === fieldName) | |
); | |
// Check for unexpected fields in the request body | |
const unexpectedFields = Object.keys(requestBody).filter((fieldName) => !validFields.includes(fieldName)); | |
// If there are unexpected fields, include as error | |
unexpectedFields.forEach(fieldName => { | |
validationErrors.push({ | |
field: fieldName, | |
message: `Field '${fieldName}' is not expected in the request body.` | |
}); | |
}); | |
// Validate request payload with Prisma Schema fields | |
for (const field of modelSchema.fields) { | |
const fieldName = field.name; | |
const fieldType = field.type; | |
// Check if the field is required but missing in the request body | |
if (field.isRequired && !field.hasDefaultValue && !(fieldName in requestBody)) { | |
validationErrors.push({ field: fieldName, message: `Field '${fieldName}' is required.` }); | |
} | |
// Check if the field type matches the expected type | |
if (fieldName in requestBody && typeof requestBody[fieldName] !== fieldType.toLowerCase()) { | |
validationErrors.push({ field: fieldName, message: `Field '${fieldName}' must be of type '${fieldType}'.` }); | |
} | |
// Check if the field is a list but not provided as an array | |
if (field.isList && !(fieldName in requestBody) && !Array.isArray(requestBody[fieldName])) { | |
validationErrors.push({ field: fieldName, message: `Field '${fieldName}' must be an array.` }); | |
} | |
// Check if the field is generated and provided in the request body | |
if (field.isGenerated && fieldName in requestBody) { | |
validationErrors.push({ field: fieldName, message: `Field '${fieldName}' is generated and cannot be provided in the request.` }); | |
} | |
// Check if the field is automatically updated and provided in the request body | |
if (field.isUpdatedAt && fieldName in requestBody) { | |
validationErrors.push({ field: fieldName, message: `Field '${fieldName}' is automatically updated and cannot be provided in the request.` }); | |
} | |
} | |
// If there are validation errors, throw an error with the details | |
if (validationErrors.length > 0) { | |
const validationError = new Error('Validation Failed'); | |
validationError.code = 'VALIDATION_ERROR'; | |
validationError.details = validationErrors; | |
throw validationError; | |
} | |
return requestBody; | |
} catch (error) { | |
throw error; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I'm using this code to plug into an ExpressJS application to validate the request body, based on the Prisma Schema.
The example below, will check the req.body against the "Character" model from Prisma.