1

My question is related to this article: Etsy API Image upload error but from a C# point of view.

Everything else works, eg I'm able to make an authenticated call to Etsy to create listings but now I've started getting an error "The request body is too large" when trying to attach images to an Etsy listing. The request used to work as I have an example response, but now it simple fails.

What I normally do is to set up a Rest Client with the keys, tokens from Etsy. Then I set up a Rest Request and pass it to the Rest Client's Execute method viz:

...
// Set up the rest client...
RestClient restClient = new RestClient();

restClient.BaseUrl = new System.Uri("https://openapi.etsy.com/v2/");
restClient.Authenticator = RestSharp.Authenticators.OAuth1Authenticator.ForProtectedResource(ConsumerKey, ConsumerSecret, PermanentAccessTokenKey, PermanentAccessTokenSecret);


// Set up the request...
RestRequest request = new RestRequest();

request.Resource = "An Etsy end point";
request.Method = Method.POST;
...

IRestResponse response = restClient.Execute(request);
...

I'm using RestSharp to handle the OAuthentication.

The main bit of interest is this:

...
                        request.AddHeader("Content-Type", "multipart/form-data");
                        request.AlwaysMultipartFormData = true;
                        request.AddParameter("image", localImageFilenames[i]);
                        request.AddParameter("type", "image/" + imageType);
                        request.AddParameter("rank", imageRank++);
                        request.AddFile("image", imageByteArray, localImageFilenames[i], "image/" + imageType);

                        request.Resource = "/listings/{0}/images".Replace("{0}", etsyListingId.ToString()); // eg "/listings/559242925/images";
                        request.Method = Method.POST;
                        response = restClient.Execute(request);

...

Where the response is:

"StatusCode: BadRequest, Content-Type: text/plain;charset=UTF-8, Content-Length: 29)"
    Content: "The request body is too large"
    ContentEncoding: ""
    ContentLength: 29
    ContentType: "text/plain;charset=UTF-8"
    Cookies: Count = 3
    ErrorException: null
    ErrorMessage: null
    Headers: Count = 9
    IsSuccessful: false
    ProtocolVersion: {1.1}
    RawBytes: {byte[29]}
    Request: {RestSharp.RestRequest}
    ResponseStatus: Completed
    ResponseUri: {https://openapi.etsy.com/v2/listings/605119036/images}
    Server: "Apache"
    StatusCode: BadRequest
    StatusDescription: "Bad Request"
    content: "The request body is too large"

The main routine then that takes a connected rest client:

    /// <summary>
    /// Upload and attach the list of images to the specified Etsy listing id.
    /// </summary>
    /// <param name="restClient">Connected Etsy client</param>
    /// <param name="localImageFilenames">List of local images to attach to the listing (ordered in rank order).</param>
    /// <param name="etsyListingId">The Etsy listing's listing id to which images will be attached.</param>
    public void AttachImagesToProduct(RestClient restClient, List<string> imageFilenames, int etsyListingId, string localTemporaryDirectory)
    {
        int imageRank = 1;
        string localImageFilename = null;
        List<string> localImageFilenames = new List<string>();


        // Before we reattach images, Etsy only caters for local image filesname eg ones that reside on the user's PC (and not http://...).
        // So, if the images beign with http... then we need to download them locally, upload them and then delete...
        for (int i = 0; i < imageFilenames.Count; i++)
        {
            if (imageFilenames[i].ToLower().Trim().StartsWith("http"))
            {
                // Download...
                localImageFilename = Orcus.CommonLibrary.Images.DownloadRemoteImageFile(imageFilenames[i], localTemporaryDirectory);
            }
            else
            {
                localImageFilename = imageFilenames[i];
            }

            if (!string.IsNullOrEmpty(localImageFilename))
            {
                localImageFilenames.Add(localImageFilename);
            }
        }

        for (int i = 0; i < localImageFilenames.Count; i++)
        {
            try
            {
                if (File.Exists(localImageFilenames[i]) && etsyListingId > 0)
                {
                    // https://stackoverflow.com/questions/7413184/converting-a-jpeg-image-to-a-byte-array-com-exception
                    // https://blog.tyrsius.com/restsharp-file-upload/
                    // https://nediml.wordpress.com/2012/05/10/uploading-files-to-remote-server-with-multiple-parameters/
                    // And also sample code from https://github.com/ChrisGraham84/EtsyAPIConsumer
                    using (MemoryStream ms = new MemoryStream())
                    {
                        Image img = Image.FromFile(localImageFilenames[i]);
                        string imageType = DetermineImageType(img);
                        System.Drawing.Imaging.ImageFormat imageFormat = DetermineImageFormat(img);
                        byte[] imageByteArray;
                        RestRequest request = new RestRequest();
                        IRestResponse response;


                        img.Save(ms, imageFormat);
                        imageByteArray = ms.ToArray();

                        request.AddHeader("Content-Type", "multipart/form-data");
                        request.AlwaysMultipartFormData = true;
                        request.AddParameter("image", localImageFilenames[i]);
                        request.AddParameter("type", "image/" + imageType);
                        request.AddParameter("rank", imageRank++);
                        request.AddFile("image", imageByteArray, localImageFilenames[i], "image/" + imageType);


                        request.AddJsonBody(null);

                        request.Resource = "/listings/{0}/images".Replace("{0}", etsyListingId.ToString()); // eg "/listings/559242925/images";
                        request.Method = Method.POST;
                        response = restClient.Execute(request);
                    }                       
                }
            }
            catch (Exception ex)
            { 
                // Image n failed to up attached so skip it...
            }
        } // for...
    }

    /// <summary>
    /// Determine the image type.
    /// </summary>
    /// <param name="localImage">The local image to be eventually uploaded to Etsy.</param>
    /// <returns>The image's type.  Default is Jpeg.</returns>
    private string DetermineImageType(Image localImage)
    {
        string imageType = "jpeg";


        if (System.Drawing.Imaging.ImageFormat.Jpeg.Equals(localImage.RawFormat))
        {
            imageType = "jpeg";
        }
        else if (System.Drawing.Imaging.ImageFormat.Gif.Equals(localImage.RawFormat))
        {
            imageType = "gif";
        }
        else if (System.Drawing.Imaging.ImageFormat.Bmp.Equals(localImage.RawFormat))
        {
            imageType = "bmp";
        }
        else if (System.Drawing.Imaging.ImageFormat.Png.Equals(localImage.RawFormat))
        {
            imageType = "png";
        }
        else if (System.Drawing.Imaging.ImageFormat.Tiff.Equals(localImage.RawFormat))
        {
            imageType = "tiff";
        }

        return imageType;
    }

    /// <summary>
    /// Determines the image's image format.
    /// </summary>
    /// <param name="localImage">The local image to be eventually uploaded to Etsy</param>
    /// <returns>The image's format.  Default is Jpeg.</returns>
    private System.Drawing.Imaging.ImageFormat DetermineImageFormat(Image localImage)
    {
        System.Drawing.Imaging.ImageFormat imgFormat = System.Drawing.Imaging.ImageFormat.Jpeg;


        if (System.Drawing.Imaging.ImageFormat.Jpeg.Equals(localImage.RawFormat))
        {
            imgFormat = System.Drawing.Imaging.ImageFormat.Jpeg;
        }
        else if (System.Drawing.Imaging.ImageFormat.Gif.Equals(localImage.RawFormat))
        {
            imgFormat = System.Drawing.Imaging.ImageFormat.Gif;
        }
        else if (System.Drawing.Imaging.ImageFormat.Bmp.Equals(localImage.RawFormat))
        {
            imgFormat = System.Drawing.Imaging.ImageFormat.Bmp;
        }
        else if (System.Drawing.Imaging.ImageFormat.Png.Equals(localImage.RawFormat))
        {
            imgFormat = System.Drawing.Imaging.ImageFormat.Png;
        }
        else if (System.Drawing.Imaging.ImageFormat.Tiff.Equals(localImage.RawFormat))
        {
            imgFormat = System.Drawing.Imaging.ImageFormat.Tiff;
        }

        return imgFormat;
    }

It's not a file size problem because I've tried with a 20K image file.

I think the problem is related to me not setting some boundary in the request?? None of the "solutions" I've seen make use of OAuthentication and RestSharp.

Brian Grinstead's article https://briangrinstead.com/blog/multipart-form-post-in-c/seemed promising but I don't understand how to integrate the Rest Client that's been set up with the Etsy keys to make the authenticated call.

[EDIT]

Pointers would be very much apprieciated.

err1
  • 499
  • 9
  • 22

1 Answers1

1

We set the AlwaysMiltipartFormData to true, and used AddFileBytes in the RestRequest. Also, we added the Content-Type multipart/form-data to the parameter list insetead of the header. Maybe that works for you as well. Good luck.

Ru Chern Chong
  • 3,692
  • 13
  • 33
  • 43
Kosi
  • 61
  • 6