tinify / tinify-nodejs

Node.js client for the Tinify API.
https://tinypng.com/developers
MIT License
414 stars 74 forks source link

s3 upload store function returns empty _meta #9

Closed mmubasher closed 7 years ago

mmubasher commented 7 years ago

Upload to aws s3 does not returns uploaded image url although images get uploaded correctly. Here is the code

const upload = function (fileName, path, callback) {
  let source = tinify.fromFile(path);
  let optimizedImg = source.resize({
    method: "fit",
    width: 800,
    height: 800
  });
  let thumbImg = source.resize({
    method: "fit",
    width: 300,
    height: 300
  }); 
  const thumb = thumbImg.store({
    service: "s3",
    aws_access_key_id: config.aws.accessKey,
    aws_secret_access_key: config.aws.secretAccessKey,
    region: config.aws.region,
    path: 'bucket_thumb_path'
  });
  const optimized = optimizedImg.store({
    service: "s3",
    aws_access_key_id: config.aws.accessKey,
    aws_secret_access_key: config.aws.secretAccessKey,
    region: config.aws.region,
    path: 'bucket_path'
  });
  Promise.all([thumb, optimized]).then(uploads => {
    return callback(null, uploads);
  }).catch(err =>{
    return callback(err);
  });
};

This is what I get in uploads array

[
  {
    "_meta": {}
  },
  {
    "_meta": {}
  }
]

Also execution never reaches .catch in Promise.all. Seems like internally some rejection is not handled. Forexample if I unset bucket path I get following in console log (node:2768) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Please provide a value for key: path (HTTP 400/Validation error)

rolftimmermans commented 7 years ago

Thanks for opening a new issue. I am replacing our previous reply because we probably identified what goes wrong.

The store() method does not return a promise, it returns an instance of a class (ResultMeta) that contains metadata when the request succeeds. You can then query for specific metadata:

image.store({...}).width((err, width) => {
  // use width of image
})

Or with promises:

image.store({...}).width().then(width => ...)

If you want all metadata as an object, you can call meta() on the result, like this:

image.store({...}).meta().then(meta => ...)

Based on your example, maybe all that you have to do is call meta() on this line:

Promise.all([thumb, optimized]).then(uploads => {

...like this:

Promise.all([thumb.meta(), optimized.meta()]).then(uploads => {

We realise that the behaviour of callbacks and promises of the NodeJS client is not very well documented (it works a bit differently than most clients). We'll try to make some improvements to it in the future.

Hope this helps. I'll close this issue for now, but feel free to comment and/or reopen if you run into anything else.