5

Multipart form data file uplaod time comming error body should be object, and i am using ajv plugin also, still i am using same issue. below is my reference code.

app.js

const fastify = require('fastify')({
    logger: true
});

const Ajv = require('ajv');
const ajv = new Ajv({
    useDefaults: true,
    coerceTypes: true,
    $data: true,
    extendRefs: true
});

ajv.addKeyword("isFileType", {
    compile: (schema, parent, it) => {
        parent.type = "file";
        delete parent.isFileType;
        return () => true;
    },
});

fastify.setSchemaCompiler((schema) => ajv.compile(schema));

routes.js

schema: {
    tags: [{
        name: 'Category'
    }],
    description: 'Post category data',
    consumes: ['multipart/form-data'],
    body: {
        type: 'object',
        isFileType: true,
        properties: {
            name: {
                type: 'string'
            },
            thumb_url: {
                isFileType: true,
                type: 'object'
            },
            img_url: {
                isFileType: true,
                type: 'object'
            },
            status: {
                type: 'number',
                enum: [0, 1],
                default: 1
            }
        },
        required: ['name', 'thumb_url', 'img_url']
    },
    response: {
        201: {
            type: 'object',
            properties: categoryProperties
        }
    }
}

response

{
    "statusCode": 400,
    "error": "Bad Request",
    "message": "body should be object"
}

I suspect the error is in the way I send the data, but I am having trouble figuring it out. I have read about this error and it seems to be generated when an object is passed to formData, but I am sending a string so I don't understand why it happens. thanks in advance!

Ravi Teja
  • 649
  • 7
  • 17

1 Answers1

3

I think your configuration to manage multipart is wrong and the schema should be fixed as this working example:

const fastify = require('fastify')({ logger: true })

fastify.register(require('fastify-multipart'), {
  addToBody: true
})

const Ajv = require('ajv')
const ajv = new Ajv({
  useDefaults: true,
  coerceTypes: true,
  $data: true,
  extendRefs: true
})

ajv.addKeyword('isFileType', {
  compile: (schema, parent, it) => {
    parent.type = 'file'
    delete parent.isFileType
    return () => true
  }
})

fastify.setSchemaCompiler((schema) => ajv.compile(schema))

fastify.post('/', {
  schema: {
    tags: [{
      name: 'Category'
    }],
    description: 'Post category data',
    consumes: ['multipart/form-data'],
    body: {
      type: 'object',
      properties: {
        name: { type: 'string' },
        thumb_url: { isFileType: true },
        img_url: { isFileType: true },
        status: {
          type: 'number',
          enum: [0, 1],
          default: 1
        }
      },
      required: ['name', 'thumb_url', 'img_url']
    }
  }
}, async (req, reply) => {
  let filepath = path.join(__dirname, `${req.body.thumb_url[0].filename}-${Date.now()}`)
  await fs.writeFile(filepath, (req.body.thumb_url[0].data))

  filepath = path.join(__dirname, `${req.body.img_url[0].filename}-${Date.now()}`)
  await fs.writeFile(filepath, (req.body.img_url[0].data))

  return req.body
})

fastify.listen(3000)

Call it with this request:

curl -X POST \
  http://127.0.0.1:3000/ \
  -H 'content-type: multipart/form-data' \
  -F 'thumb_url=@/home/wks/example-file' \
  -F 'img_url=@/home/wks/example-file' \
  -F 'name=fooo'

You will get:

{
   "thumb_url":[
      {
         "data":{
            "type":"Buffer",
            "data":[
               97,
               115,
               100,
               10
            ]
         },
         "filename":"example-file",
         "encoding":"7bit",
         "mimetype":"application/octet-stream",
         "limit":false
      }
   ],
   "img_url":[
      {
         "data":{
            "type":"Buffer",
            "data":[
               97,
               115,
               100,
               10
            ]
         },
         "filename":"example-file",
         "encoding":"7bit",
         "mimetype":"application/octet-stream",
         "limit":false
      }
   ],
   "name":"foo",
   "status":1
}
Manuel Spigolon
  • 11,003
  • 5
  • 50
  • 73