The problem.
My customers frequently upload images of wrong size or type e.g. of too small resolution, vector instead of raster etc.
The desired decision would be to add a custom validators to model fields. I suppose this should be a pretty common problem, but I can’t find any official document on the topic.
So which is the proper way to add a custom validation rules and to show user corresponding error messages in admin area?
To achieve some validation on fields you can use lifecycles.
module.exports = {
lifecycles: {
// Called before an entry is created
beforeCreate(data) {
// calling a custom services which handles the validation process
// and returns a message if something is wrong and true if everything is ok
let message = await strapi.services.zzz.validation(data);
if (message != true){
throw new Error(message);
}
},
},
};
The problem here is that the image gets uploaded when you select it inside the media field. So when you create a new entry in your collection type the image already exists.
To achieve custom validation during media upload you should use extensions.
The file you need is located here: ./node_modules/strapi-plugin-upload/services/Upload.js. Copy its content to ./extensions/upload/services/Upload.js and add your custom logic inside it.
Thank you!
One more thing. Is it possible to pass the error messages to the client side, so the custom error message would appear near the corresponding input inside the form just like the native validation messages?
File ./node_modules/strapi-plugin-upload/controllers/upload/admin.js, copy to ./extensions/upload/controllers/upload/admin.js, modify the uploadFiles function:
async uploadFiles(ctx) {
const {
state: { userAbility, user },
request: { body, files: { files } = {} },
} = ctx;
const uploadService = strapi.plugins.upload.services.upload;
const pm = strapi.admin.services.permission.createPermissionsManager(
userAbility,
ACTIONS.create,
fileModel
);
if (!pm.isAllowed) {
throw strapi.errors.forbidden();
}
const data = await validateUploadBody(body);
// ----------------------------------------
// here I do some validation before the upload process.
// throw strapi.errors.badRequest('');
let validationFail = true;
if (validationFail) {
throw strapi.errors.badRequest('WRONG SIZE!!11');
}
// ----------------------------------------
const uploadedFiles = await uploadService.upload({ data, files }, { user });
ctx.body = pm.sanitize(uploadedFiles, { action: ACTIONS.read, withPrivate: false });
},
Actually I meant a bit different. Usually particular validation constraints belong to specific fields. I mean for some attributes it’s ok to use svg, in others only raster are required, so validation better be related to specific model attribute instead of all files upload.
What i meant was this type of in-form attribute specific error message
Anyway I dug up some code in strapi-plugin-content-manager and in-form error messages like that generated on back-end seem impossible right now.
Actually the error message about uniqueness validation fail (back-end generated) looks like this Kind of not really readable to end user
Hi there!
Any updates on this?
I’m trying to achieve this result but it seems it doesn’t work for me. Following the same steps won’t work.
I’m copying the required files from strapi-plugin-upload to extensions folder, but even so, the upload function used is that from strapi-plugin-upload, not the one just created.
Hello @sunnyson, I have a question, is this process will work when deploying to production? In my case, it’s not. I don’t know why, it only works on the development side.
There is actually a pretty easy way to accomplish this in Strapi 4,
The Forms use Yup validation so you can hack into that system to prompt a custom error message on the input itself and also show a global error message while you’re at it.
Just create a lifecycles.js file inside the content-types folder, here is some example code to help you get started
async beforeUpdate(event) {
const { data } = event.params;
const { YupValidationError } = require("@strapi/utils").errors;
if (data.description) {
const errorMessage = {
"inner": [
{
"name": "ValidationError", // Always set to ValidationError
"path": 'description', // Name of field we want to show input validation on
"message": 'some custom error message', // Input validation message
}
]
};
const globalErrorMessage = "You have some issues";
throw new YupValidationError(errorMessage, globalErrorMessage);
}
},```
more info at [Strapi lifecycle hooks docs](https://docs.strapi.io/developer-docs/latest/development/backend-customization/models.html#lifecycle-hooks)
The errors middleware turns all the Errors to internal server error, but should not. Terminal is good, but I would like the UI to get the right validation error
strapi version 4.4.7, same code is working for strapi 4.1.something
and my code was copied from your snippet, so it is basically the same