I connected my Node.js project to Cloudinary and I was able to successfully upload both public and private assets to the same folder in cloudinary, I named it "development".
I figured that development/id
is the intended publicId, and that worked for public assets.
However, For private assets, that did not work. Beside the development/id
path, I also tried every level of image/private/s--KEYHERE--/v123456789/development/publicIdOfPrivateAsset'
for every attempt below, but I ended up with a resource not found error
(Variations of the error are listed below)
Upload Code
const multer = require('multer')
// Defined in .env: CLOUDINARY_URL=cloudinary://my_key:my_secret@my_cloud_name
const cloudinary = require('cloudinary').v2
const { CloudinaryStorage } = require('multer-storage-cloudinary');
const CLOUDINARY_FOLDER = "development"
const storage = new CloudinaryStorage({
cloudinary: cloudinary,
params: {
folder: CLOUDINARY_FOLDER,
// type: 'private' // Used for creating the private asset
},
});
const upload = multer({ storage: storage });
app.post('/api/v1/media', upload.single('image'), (req, res) => {
return res.json({ image: req.file.path });
})
Getting the asset using api.resource
http://localhost:5000/api/v1/media/development/publicIdOfPrivateAsset
app.get('/api/v1/media/:folder/:id', (req, res) => {
const { folder, id } = req.params
cloudinary.api.resource(`${folder}/${id}`, (error, result) => {
if (error) return console.log(error)
return res.json(result)
});
})
Response
{
message: 'Resource not found - development/publicIdOfPrivateAsset',
http_code: 404
}
Destroying the asset using uploader.destroy
http://localhost:5000/api/v1/media/publicIdOfPrivateAsset
app.delete('/api/v1/media/:publicId', (req, res) => {
const { publicId } = req.params;
cloudinary.uploader.destroy('development/' publicId, (err, result) => {
if (err) { console.log(err); return res.status(500).json(err); }
return res.status(200).json(result)
})
})
Response:
{
"result": "not found"
}
Deleting resources using api.delete_resources
In this example, I included private and public assets in the same request. The public one worked, the private one did not.
Request:
http://localhost:5000/api/v1/media
Body:
{
"publicIds": [
"development/publicIdOfPublicAsset",
"development/publicIdOfPrivateAsset"
]
}
Node.js
app.delete('/api/v1/media', (req, res) => {
const { publicIds } = req.body;
cloudinary.api.delete_resources(publicIds, (err, result) => {
if (err) { console.log(err); return res.status(500).json(err); }
return res.status(200).json(result)
})
})
Response:
{
"deleted": {
"development/publicIdOfPublicAsset": "deleted",
"development/publicIdOfPrivateAsset": "not_found"
},
"deleted_counts": {
"development/publicIdOfPublicAsset": {
"original": 1,
"derived": 0
},
"development/publicIdOfPrivateAsset": {
"original": 0,
"derived": 0
}
},
"partial": false,
"rate_limit_allowed": 500,
"rate_limit_reset_at": "2021-10-17T14:00:00.000Z",
"rate_limit_remaining": 494
}
What am I missing? Thank you
CodePudding user response:
In Cloudinary an asset is unique/identified by not only the public_id
but only when in combination with the resource_type
and type
. Therefore, the below assets with the same public_id (sample
) are actually different entities:
image/upload/sample
image/private/sample
video/upload/sample
video/authenticated/sample
API methods default the value of certain optional parameters if they are not provided. This includes the 'resource_type' (defaulted to "image") and also 'type' (defaulted to "upload").
In your case, since you are trying to search/delete a private image you would need to explicitly pass the 'type' parameter and set its value to 'private'. Otherwise, what will currently happen is that your code would try to delete the right public_id, however, it would be defaulting to 'type' of 'upload' and therefore not find the file you are looking for. This is why it finds the "upload" asset and not the "private" one.
You need to include the specific type/resource_type in your request if they are different from the default. Here, you need to pass "type": "private"
in all your example API calls.