0

There seems to be lack of documentation on this topic. I'm trying to upload an image and set it to avatar: { type: Types.CloudinaryImage } in my Keystone model.

I'm posting content as multipart form data with the following structure: avatar: <raw_data>. Here is how I handle this in my API:

exports.upload_avatar = function(req, res) {
    if (!req.files.avatar) {
        console.info('Request body missing');
        return res.status(400).json({ message: 'Request body missing', code: 20 });
    }
    req.current_user.avatar = req.files.avatar;
    req.current_user.save();
} 

where current_user is a mongoose model. What I find confusing is how to set my CloudinaryImage type field to the data I receive in the API.

Nikolay Derkach
  • 1,734
  • 2
  • 22
  • 34

3 Answers3

0

So, rather than just setting the avatar to the raw data (which would work fine for e.g. a string field), you'll need to go through the update handler, which calls to the {path}_upload special path in cloudinary image.

You should then be able to do avatar.getUpdateHandler, perhaps following this example.

Jake Stockwin
  • 262
  • 3
  • 10
  • Hm, I've tried `req.current_user.getUpdateHandler(req).process(req.files, {fields: 'avatar'}, function(err) {})`, as well as invoking handler on the `avatar` field. Doesn't cause any errors, although the file is not uploaded either. – Nikolay Derkach Feb 09 '17 at 14:30
0

I would like to share what worked for me. The process is kind of strange but by adding in this code, all of the model validation works just fine and cloudinary uploads are set.

post(req, res, next) {
  const newBundle = new Bundle(); //A mongoose model
  newBundle.getUpdateHandler(req).process(req.body, (err) => {
    if (err) {
      return res.status(500).json({
        error: err.message,
      });
    }
    return res.json(newBundle);
  });
}

When posting to the endpoint, all you need to do is make sure you set your file fields to be {databaseFieldName}_upload.

Jt oso
  • 57
  • 1
-1

Ok after some digging through the source code, I figured out a way to do that:

exports.upload_avatar = function(req, res) {
    req.current_user.getUpdateHandler(req).process(req.files, {fields: 'avatar'}, function(err) {
      if (err) {
          return res.status(500).json({ message: err.message || '', code: 10 });
      }
      res.send('');
    });
}

I had the following gotchas:

  • use getUpdateHandler to update CloudinaryImage field.
  • use "magic" naming for multipart form data fields you POST to your API: {field_name}_upload, which in my case would be avatar_upload.
  • process req.files, which is a dictionary with your field names as keys and your file data as values. req.body is empty due to some post-processing with multer.
  • invoke update handler on your keystone model (you need to fetch it with find first) rather than on a specific field. Then specify {fields: <>} to limit its scope, otherwise you could have some issues like validation errors trying to update the whole object.
Nikolay Derkach
  • 1,734
  • 2
  • 22
  • 34