Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Json schema validation fails with fastify-multipart #525

Closed
guerrap opened this issue Sep 7, 2021 · 3 comments
Closed

Json schema validation fails with fastify-multipart #525

guerrap opened this issue Sep 7, 2021 · 3 comments
Labels
help wanted Extra attention is needed

Comments

@guerrap
Copy link

guerrap commented Sep 7, 2021

💬 Question here

Hello,
I'm trying to implement an API using fastify-multipart plugin, that applies a schema validation of a simple body.
When calling the API I'm getting a bad request error body.name should be string, but the body.name field is correctly sent as a string, so I don't understand why the validation fails. Am I missing something? I followed the example in the README.
Below there's the code for both the server and the client.

server:

const util = require("util");
const { pipeline } = require("stream");
const pump = util.promisify(pipeline);
const fs = require("fs");

const fastify = require("fastify")({
  logger: true,
  ajv: {
    customOptions: {
      coerceTypes: false,
      removeAdditional: false,
    },
  },
});

(async () => {
  const onFile = async (part) => {
    await pump(part.file, fs.createWriteStream(part.filename));
  };

  fastify.register(require("fastify-multipart"), {
    limits: {
      fieldNameSize: 100, // Max field name size in bytes
      fieldSize: 100, // Max field value size in bytes
      fields: 10, // Max number of non-file fields
      fileSize: 1000000, // For multipart forms, the max file size in bytes
      files: 1, // Max number of file fields
      headerPairs: 2000, // Max number of header key=>value pairs
    },
    attachFieldsToBody: true,
    sharedSchemaId: "#mySchemaId",
    onFile,
  });

  fastify.post(
    "/upload/files",
    {
      schema: {
        body: {
          type: "object",
          required: ["name", "lastname", "metadata"],
          properties: {
            name: { type: "string" },
            lastname: { type: "string" },
            metadata: {
              type: "object",
              required: ["amount", "kind", "color"],
              properties: {
                amount: {
                  type: "string",
                },
                kind: {
                  type: "string",
                },
                color: {
                  type: "object",
                  required: ["main"],
                  properties: {
                    main: {
                      type: "string",
                    },
                    secondary: {
                      type: "string",
                    },
                  },
                },
              },
            },
          },
        },
      },
    },
    async function (req, reply) {
      reply.send("ok");
    }
  );

  fastify.listen(3000, (err, address) => {
    if (err) throw err;
    console.info(`listening on port ${address}`);
  });
})();

client:

const axios = require("axios");
const FormData = require("form-data");
const fs = require("fs");

const payload = {
  amount: "amount",
  kind: "kind",
  color: { main: "yellow", secondary: "green" },
};

const data = new FormData();
data.append("name", "first-name");
data.append("lastname", "last-name");
data.append("metadata", JSON.stringify(payload));
data.append("file", fs.createReadStream("/home/cicuz/Desktop/TODO"));

const config = {
  method: "post",
  url: "http://localhost:3000/upload/files",
  headers: {
    ...data.getHeaders(),
  },
  data: data,
  maxContentLength: Infinity,
  maxBodyLength: Infinity,
};

axios(config)
  .then(function (response) {
    console.log(JSON.stringify(response.data));
  })
  .catch(function (error) {
    console.log(error);
  });

full error:

"err": {
  "type": "Error",
  "message": "body.name should be string",
  "stack": "...",
  "validation": [
    {
      "keyword": "type",
      "dataPath": ".name",
      "schemaPath": "#/properties/name/type",
      "params": { "type": "string" },
      "message": "should be string"
    }
  ],
  "validationContext": "body"
},
"msg": "body.name should be string"

Your Environment

  • node version: 15
  • fastify version: 3.21.0
  • fastify-multipart version: 4.0.7
  • os: Linux
@radomird
Copy link

radomird commented Oct 1, 2021

Hi @guerrap, thanks for submitting this issue.

There are two problems in your case.

1st problem: The way you are defining the JSON schema for validation is not the same as it's mentioned in the documentation. The way you defined the validation for the name and lastname fields was:

name: { type: "string" },
lastname: { type: "string" },

but it should be like this:

name: {
  properties: {
    value: { 
      type: 'string',
    }
  }
},
lastname: {
  properties: {
    value: { 
      type: 'string',
    }
  }
},

The reason is that the plugin first converts the non-file fields into a object that looks like this:

name: {
  fieldname: "name",
  value: "first-name",
  fieldnameTruncated: false,
  valueTruncated: false,
  fields: body
}

After the conversion the object gets validated against the defined schema. The documentation of the fastify-multipart plugin doesn't mention this conversion, unfortunately. Once you change your schema - you will not get the error you mentioned.

I've opened an issue to improve the documentation, you can find it here: fastify/fastify-multipart#277

2nd problem: (which you would only notice after you fix the 1st problem) is that you are trying to sent a non-file field with a stringified JSON object as the value. At this moment the plugin doesn't support having objects as the field value.
I've opened another issue to support this use-case, you can find it here: fastify/fastify-multipart#278

@guerrap
Copy link
Author

guerrap commented Oct 1, 2021

Hi, thank you for your answer

@climba03003
Copy link
Member

I will close this issue and you can keep track on the issue open by radomird on fastify-multipart.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants