Closed olivierto closed 5 years ago
Hi, I could be faster to help you if you can provide me a complete snippet to replicate the issue because I need to know how you configure the ajv instace and the http request you send (a CURL would be really helful)
thanks for you reply, but after few hours i get this to get working. Here is my setup fastify
const ajv = new Ajv({
// removeAdditional: "all",
useDefaults: true,
coerceTypes: true,
$data: true,
extendRefs: true
});
require('ajv-keywords')(ajv);
// Add isFileType for file / multipart-form data validation
ajv.addKeyword("isFileType", {
compile: (schema, parent, it) => {
// Change the schema type, as this is post validation it doesn't appear to error.
(parent as any).type = "file";
delete (parent as any).isFileType;
return () => true;
},
});
fastify.setSchemaCompiler((schema: any) => ajv.compile(schema));
The first problem occurs in my schema where the isFileType property wasn't set on the body object.
{
"consumes": ["multipart/form-data"],
"body": {
"type": "object",
"isFileType": true,
"properties": {
"urbanFile": {
"isFileType": true,
"type": "object"
},
"authorizationType": {
"type": "string",
"enum": [
"buildingPermit",
"planningPermit",
"demolitionPermit"
]
},
}
I still got a problem at this point because the body was left blank with no data in it... i add to set manually a custom content parser to fill body with fields values from form data (based on this see this issue on fastify/swagger)
fastify.addContentTypeParser("multipart/form-data", (req, done) => {
const body = {} as any;
const stream = new Busboy({ headers: req.headers }) as any;
req.on("error", (err) => {
stream.destroy();
done(err);
});
stream.on("field",(key:string,value:string)=>{
body[key] = value;
});
stream.on("finish", () => {
const dot = require('dot-object');
dot.object(body);
done(null, body)
});
stream.on("file", (field:string, file:NodeJS.ReadableStream, filename:string, encoding:string, mimetype:string) => {
file.on("data", (data) => {
if (! body[field]) {
body[field] = [];
}
body[field].push(data);
});
file.on("end", () => {
body[field] = Buffer.concat(body[field].map((part:any) => isBuffer(part) ? part : Buffer.from(part)));
});
});
req.pipe(stream);
});
it seems that fastify/multipart plugin doesn't handle fields in formdata... may be it will be a good PR ? If so i'll try to work on this next week.
Thanks
I looked at the problem and there are multiple aspects to investigate. Let me explain in order to understand what we can do/fix 👍
Your 400 bad request
error is due to the validation of the HTTP body
. When you POST an http multipart the body
is empty. The validation is applied anyway and it fails of course.
To explain better let see the two difference HTTP request:
MULTIPART
curl -X POST \
http://127.0.0.1:3000/ \
-H 'content-type: multipart/form-data' \
-F authorizationType=buildingPermit \
-F 'urbanFile=@C:\Users\behem\Downloads\example-file'
APPLICATION JSON
curl -X POST \
http://127.0.0.1:3000/ \
-H 'Content-Type: application/json' \
-d '{
"authorizationType": "buildingPermit",
"urbanFile": "----BASE64 FILE---"
}'
All these two HTTP request works but with different settings and different approach.
The issue you have linked is correctly related to your issue (and there is also the problem to show on swagger the file upload).
It is good that you have found this https://github.com/fastify/fastify-swagger/issues/47#issuecomment-463618725 workaround, and I think that is the correct one for now.
I'm not sure adding the custom field on ajv is right, because json-schema implement the contentMediaType parameter, but this is an implement detail.
I think we should improve the file management (here and in swagger plugin), but I need to figure out better where apply the fix (because it is the fastify core that trigger the validation on the body
field for example).
So I would leave this issue open for now in order to think a "final" solution ✌
cc @mcollina
Hello there! But I still get an error :
{
"statusCode": 400,
"error": "Bad Request",
"message": "body should be object",
"code": "BadRequest"
}
@chenchuraviteja what is your validation schema ?
validation schema
schema: { tags: [{ name: 'Category' }], description: 'Post category data', consumes: [ "multipart/form-data" ], body: { type: 'object', properties: { name: { type: 'string' }, thumg_url: { isFileType: true, type: 'object' }, img_url: { isFileType: true, type: 'object' }, status: { type: 'number', enum: [0, 1], default: 1 } }, required: ['name', 'thumg_url', 'img_url'] }, response: { 201: { type: 'object', properties: categoryProperties } } }
@chenchuraviteja Sorry, but you posted the same message here and here https://github.com/fastify/fastify-swagger/issues/47#issuecomment-567327816 So, please open an issue and describe your problem, filling all the info as described in the issue template.
Only in this way we could help you
Hello there! I'm trying to get fastify-multipart form and fastify/ajv schema validation to work together in a restfull api. But I still get an error :
I've extented AJV with a fileType
Here is my schema
and here is my handler function
Is this a bug ? or am I doing something wrong? any help on this would be much much appreciated.
Cheers, Olivier