Question

I'm struggling with a ruby script to upload some pictures to moodstocks using their http interface

here is the code that I have so far

curb = Curl::Easy.new
curb.http_auth_types = :digest
curb.username = MS_API
curb.password = MS_SECRET
curb.multipart_form_post = true

Dir.foreach(images_directory) do |image|
  if image.include? '.jpg'
    path = images_directory + image
    filename = File.basename(path, File.extname(path))

    puts "Upload #{path} with id #{filename}"

    raw_url = 'http://api.moodstocks.com/v2/ref/' + filename
    encoded_url = URI.parse URI.encode raw_url

    curb.url = encoded_url
    curb.http_put(Curl::PostField.file('image_file', path))
  end
end

and this is the error that I get

/Library/Ruby/Gems/2.0.0/gems/curb-0.8.5/lib/curl/easy.rb:57:in `add': no implicit        conversion of nil into String (TypeError)
    from /Library/Ruby/Gems/2.0.0/gems/curb-0.8.5/lib/curl/easy.rb:57:in `perform'
    from upload_moodstocks.rb:37:in `http_put'
    from upload_moodstocks.rb:37:in `block in <main>'
    from upload_moodstocks.rb:22:in `foreach'
    from upload_moodstocks.rb:22:in `<main>'

I think the problem is in how I give the argument to the http_put method, but I have tried to look for some examples of Curl::Easy.http_put and have found nothing so far.

Could anyone point me to some documentation regarding it or help me out on this.

Thank you in advance

Was it helpful?

Solution

There are several problems here:

1. URI::HTTP instead of String

First, the TypeError you encounter comes from the fact that you pass a URI::HTTP instance (encoded_url) as curb.url instead of a plain Ruby string.

You may want to use encoded_url.to_s, but the question is why do you do this parse/encode here?

2. PUT w/ multipart/form-data

The second problem is related to curb. At the time of writing (v0.8.5) curb does NOT support the ability to perform a HTTP PUT request with multipart/form-data encoding.

If you refer to the source code you can see that:

  1. the multipart_form_post setting is only used for POST requests,
  2. the put_data setter does not support Curl::PostField-s

To solve your problem you need an HTTP client library that can combine Digest Authentication, multipart/form-data and HTTP PUT.

In Ruby you can use rufus-verbs, but you will need to use rest-client to build the multipart body.

There is also HTTParty but it has issues with Digest Auth.

That is why I greatly recommend to go ahead with Python and use Requests:

import requests
from requests.auth import HTTPDigestAuth
import os

MS_API_KEY = "kEy"
MS_API_SECRET = "s3cr3t"

filename = "sample.jpg"

with open(filename, "r") as f:
  base = os.path.basename(filename)
  uid = os.path.splitext(base)[0]

  r = requests.put(
    "http://api.moodstocks.com/v2/ref/%s" % uid,
    auth = HTTPDigestAuth(MS_API_KEY, MS_API_SECRET),
    files = {"image_file": (base, f.read())}
  )

  print(r.status_code)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top