Closed Gustavo-Murdiga88 closed 6 months ago
I come up with this solution to tackle the problem, but I'm not entirely satisfied with it and am still seeking a more appropriate way to handle it.
fastify.register(multipart, {
attachFieldsToBody: "keyValues",
onFile: async (part) => {
const buff = await part.toBuffer();
part.value = {
filename: part.filename,
file: buff,
};
},
});
fastify.register(swagger, {
...
transform: (data) => {
const jsonSchema = jsonSchemaTransform(data);
normalizeFileFields(jsonSchema.schema);
return jsonSchema;
},
});
const normalizeFileFields = (obj: Record<string, any>) => {
for (let key in obj) {
if (typeof obj[key] === "object" && obj[key] !== null) {
if (obj[key].hasOwnProperty("filename") && obj[key].hasOwnProperty("file")) {
obj.type = "file";
} else {
normalizeFileFields(obj[key]);
}
}
}
return obj;
};
Dude, I am so glad you helped me, your answer was very good, but it does not work 100%, I had to change some parts of your code.
Then your code in my implementation should be like this.
const normalizeFileFields = (obj: Record<string, any>) => {
let routeContainsFile = false;
if (obj.hasOwnProperty("consumes") && obj.consumes.includes("multipart/form-data")) {
routeContainsFile = true;
}
for (let key in obj) {
if (typeof obj[key] === "object" && obj[key] !== null) {
if (key === "body" && routeContainsFile) {
obj[key] = {
type: "object",
required: ["file"],
properties: {
file: { type: 'file' },
}
};
} else {
normalizeFileFields(obj[key]);
}
}
}
return obj;
};
And I need to change my implementation for this.
app.withTypeProvider<ZodTypeProvider>().route({
method: "POST",
url: "/files/:filename",
schema: {
tags: ["Upload"],
summary: 'Insert a file from CloudFlare R2 or AWS',
params: z.object({
filename: z.string(),
}),
consumes: ["multipart/form-data"],
body: z.custom<MultipartFile>(),
},
handler: async (request, reply) => {
const data = request.body;
if (!data.file) {
return reply.status(400).send({
message: "Please send a file"
})
}
const buffer = data.file;
await client.putObject({
Bucket: process.env.BUCKET_NAME,
Key: request.params.filename,
Body: buffer,
}).promise();
return reply.status(201).send({ message: "File uploaded" })
}
});
Then my end point starts working with the input file correctly. See it here.
Thank you so much for your help.
Today I use this approach, but the input does not work on my docs.
schema: { tags: ["Upload"] params: z.object({ filename: z.string(), }), consumes: ["multipart/form-data"], body: z.custom<Multipart>() },
How I can write for the input works on my docs?
This is the output of this code: