Lurk / cloudinary_rs

unofficial cloudinary rust SDK
4 stars 6 forks source link

Upload image issue #37

Open DhvaniBhesaniya opened 1 month ago

DhvaniBhesaniya commented 1 month ago

i am using the upload method just as instructed but i am getting this parse error. uploading is working fine , in the cloudinary it is being uploaded. i am using data url as a source to upload the image.

here is the error : " Upload result :: , Err(failed to parse:

{"asset_id":"c49b1d4902a9dfc2bfee942a38d675c0","public_id":"pwoyepnl4re9skaban5j","version":1728368129,"version_id":"d12154246f5b4b4fe949d8f6ddb8d59f","signature":"209f3fc898796e3d82d59cc6e193f4c544aa39cb","width":223,"height":226,"format":"png","resource_type":"image","created_at":"2024-10-08T06:15:29Z","tags":[],"bytes":4824,"type":"upload","etag":"0652a25b4542ff8a0312f814c6c9a8b1","placeholder":false,"url":"http://res.cloudinary.com/djigcn0dy/image/upload/v1728368129/pwoyepnl4re9skaban5j.png","secure_url":"https://res.cloudinary.com/djigcn0dy/image/upload/v1728368129/pwoyepnl4re9skaban5j.png","asset_folder":"","display_name":"pwoyepnl4re9skaban5j","api_key":"4273989199567"}

Caused by: data did not match any variant of untagged enum UploadResult) "

for now i have done like if it is ok then from the success response i will takew the secure url , but if this error comes i am extracting the secure url from the error msg, which in coding sense not good , can you help me to solve this error ,

here below is my code.

pub async fn upload_image_to_cloudinary(profile_img: &str) -> Result<String, String> { let cloud_name = gett::("CLOUDINARY_CLOUD_NAME"); let api_key = gett::("CLOUDINARY_API_KEY"); let api_secret = gett::("CLOUDINARY_API_SECRET");

let options = UploadOptions::new();
let upload = Upload::new(
    api_key.to_string(),
    cloud_name.to_string(),
    api_secret.to_string(),
);

// Upload the image to Cloudinary
let upload_result = upload
    .image(Source::DataUrl(profile_img.into()), &options)
    .await;

println!("Upload result :: , {:?}", upload_result);

match upload_result {
    // If successful, return the secure URL
    Ok(result) => {
        if let UploadResult::Success(response) = result {
            Ok(response.secure_url)
        } else {
            Err("Upload failed, but no valid URL returned.".to_string())
        }
    }
    // Handle errors
    Err(e) => {
        // Attempt to parse and extract the secure_url from the error message
        let error_message = format!("{:?}", e);

        // Use regex to find the secure_url in the error message
        let re = Regex::new(r#""secure_url":"(https://[^"]+)""#).unwrap();
        if let Some(captures) = re.captures(&error_message) {
            if let Some(secure_url) = captures.get(1) {
                return Ok(secure_url.as_str().to_string());
            }
        }

        Err("Failed to extract secure_url from error".to_string())
    }
}

} can you check if there is any problem ?.

Lurk commented 1 month ago

I see they changed the response schema in the documentation and the error message you posted, but I can not get a response in that shape.

Anyway, I know how to fix that (one more enum variant here: https://github.com/Lurk/cloudinary_rs/blob/main/src/upload/result.rs#L27). I'm still trying to figure out how to test, though.

DhvaniBhesaniya commented 1 month ago

i have trield to update the code structure here base on the response , and its working fine, with a success response casting to UploadResult success Response,

here is what i have tries to change and update .

[derive(Clone, Deserialize, Debug)]

pub struct Eager { pub transformation: Option, pub width: Option, pub height: Option, pub bytes: Option, pub format: Option, pub url: Option, pub secure_url: Option, }

[derive(Clone, Deserialize, Debug)]

pub struct Response { pub asset_id: String, pub public_id: String, pub version: usize, pub version_id: String, pub signature: String, pub width: usize, pub height: usize, pub format: String, pub resource_type: String,

[serde(deserialize_with = "deserialize_from_str")]

pub created_at: DateTime<Utc>,
pub tags: Vec<String>,
pub bytes: usize,
pub r#type: String,
pub etag: String,
pub placeholder: bool,
pub url: String,
pub secure_url: String,
pub folder: Option<String>,
pub overwritten: Option<bool>,
pub original_filename: Option<String>,
pub original_extension: Option<String>,
pub api_key: String,
pub eager: Option<Vec<Eager>>,

}

pub async fn image(&self, src: Source, options: &UploadOptions<'_>) -> Result { let client = Client::new(); let file = match src { Source::Path(path) => prepare_file(&path).await?, Source::Url(url) => Part::text(url.as_str().to_string()), Source::DataUrl(base64) => Part::text(base64), }; let multipart = self.build_form_data(options).part("file", file); let url = format!( "https://api.cloudinary.com/v1_1/{}/image/upload", self.cloud_name );

    // Send the request
    let response = client
    .post(&url)
    .multipart(multipart)
    .send()
    .await
    .context(format!("upload to {}", url))?;

// Capture the response status before consuming the response
let status = response.status();

// Get the response text (this consumes the response)
let text = response.text().await?;
println!("Cloudinary response text: {:?}", text);

// Check if the response was successful based on the saved status
if status.is_success() {
    // Parse success response into UploadResult::Success
    let parsed_response: Response = serde_json::from_str(&text)
        .context(format!("Failed to parse Cloudinary success response:\n\n {}", text))?;
    return Ok(UploadResult::Success(Box::new(parsed_response)));
}

    // Otherwise, parse it as an error
    let parsed_error: Error = serde_json::from_str(&text)
        .context(format!("Failed to parse Cloudinary error response:\n\n {}", text))?;
    Ok(UploadResult::Error(Box::new(parsed_error)))
}

i have changes the structure and upload image function. see if this helps you.

Lurk commented 1 month ago

Hey @DhvaniBhesaniya, please check the latest version. https://crates.io/crates/cloudinary/0.6.0 Note that upload_result from your first example has a new enum variant with a new response shape.

I haven't found where this change is documented, but all new Cloudinary accounts get the response in the new shape, while old accounts still get it in the old shape.

DhvaniBhesaniya commented 1 month ago

According to you new version update i am still getting parse error here " ResponseWithImageMetadata "

ERROR - failed to parse:

{"asset_id":"c38a161953bc4a6c7472a7c04a44577b","public_id":"oujlo7tngcrq9pneavst","version":1728536861,"version_id":"4c797b517cf0d5adbf3d0d196d3bfcb0","signature":"149de0e119e1d7970782d16506cfb87c4706000f","width":274,"height":184,"format":"jpg","resource_type":"image","created_at":"2024-10-10T05:07:41Z","tags":[],"bytes":4365,"type":"upload","etag":"f2e60e6cfdb2d4e3e48f2a117faaa34d","placeholder":false,"url":"http://res.cloudinary.com/djigcn0dy/image/upload/v1728536861/oujlo7tngcrq9pneavst.jpg","secure_url":"https://res.cloudinary.com/djigcn0dy/image/upload/v1728536861/oujlo7tngcrq9pneavst.jpg","asset_folder":"","display_name":"oujlo7tngcrq9pneavst","api_key":"427982931967"}

Caused by: data did not match any variant of untagged enum UploadResult

i have tries to change the response structure according to the cloudinary response schema ,

https://github.com/Lurk/cloudinary_rs/issues/37#issuecomment-2401516011

see comment .

Lurk commented 1 month ago

Hey, @DhvaniBhesaniya, please check the next version https://crates.io/crates/cloudinary/0.7.0 😀