Ruby: Rest-client multipart upload to Google drive with metadata - ruby

I am trying to perform a file upload to google drive's API using Rest calls. The API says that if you want to name the file metadata must be passed and it should be uploaded as multipart.
I am getting a '400 Bad Request' error. I think that this might be due to having multiple content types using Rest client.
RestClient::Request.execute(
:method => "post",
:url => "https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart",
:headers => {:Authorization => "Bearer #{access_token}", :content_type => 'multipart/related'},
:payload => {:metadata => "{'title' : 'testing'}", :file => File.new(file, 'rb'), :multipart => true}
)
Any help would be great! Thanks!

I believe, using the given library (rest-client), this is not possible as the request, according to Google's requirements, the multi-parts need to be ordered and must have the correct mime type for each of the multipart.
So, I'd say, the syntax you've used is closest to correct, but unfortunately the gem doesn't seem to support this [1] as of the time of this comment.
If you still are looking for a solution, the closest thing I found was digging directly into Google's API client library, where they hand-craft a multipart request with the help of hurley [2].
You can check the source code for some ideas.[3]
Hope this helps.
[1] https://github.com/rest-client/rest-client/pull/222
[2] https://github.com/lostisland/hurley
[3] https://github.com/google/google-api-ruby-client/blob/d2e51b4e7d4cb5a18cb08b2aed9c0d8ffff14b22/lib/google/apis/core/multipart.rb

Related

How to use open-uri or paperclip to download images into database and feed them to a Rest API

I am working on a data integration app which need to fetch images from one API (with XML's urls) and post the images to a rails built REST API.
I tried paperclip to download all the images however don't know how to handle the Paperclip::Attachment type when trying to post the images with HTTMultiParty.
I am thinking about use open-uri instead of paperclip which will store file into binary. Can anyone give me an example on that? And is there any good option for posting image to API apart from httmultiparty.
It's better to answer this question myself because the solution can be varied.
So image fetch and feed through api can be done by httparty(download&upload text)+paperclip(download image by url)+httmultiparty(upload image), here are some code example I use in my application.
To me, httparty is easiest way to deal with api, codes can be easily done like this:
response = HTTParty.get('url')
response = HTTParty.post('url',
:headers => 'head content',
:body => {'data':'data content'})
Code example on paperclip is here: answer on stack over flow
The important part is parsing the paperclip image to binary file, code goes:
Paperclip.io_adapters.for(productData[0].image).read
The last example is HTTmultiparty, When you pass a query with an instance of a File as a value for a PUT or POST request, the wrapper will use a bit of magic and multipart-post to execute a multipart upload,apart from that it is pretty much the same as httparty:
class ImgClient
include HTTMultiParty
base_uri 'http://localhost:3000'
end
respond = ImgClient.post('url',
:headers => head,
:query => {
:image => Paperclip.io_adapters.for(product.image)
})
Hope this will be helpful for other api newbies.

How to send DELETE request with body using ruby gem?

I am communicating with API that requires DELETE request with JSON body. This works on console:
curl -XDELETE http://api.com/endpoint_path/rest_resource
-d '{"items":[{"type":"type1","item_id":"item1"}]}'
It seems that most gems for making HTTP requests don't support DELETE request with body (I tried RestClient and Curb). Is there a way to do it using some Ruby gem (preferably Curb) or Net::HTTP?
Here's one way using HTTParty:
HTTParty.delete("http://api.com/endpoint_path/rest_resource", {
:body => '{"items":[{"type":"type1","item_id":"item1"}]}'
})
it could be used her. This is ORM for api. https://github.com/remiprev/her
Example of usage:
RestResource.destroy_existing(id, body_params)
I also spent some time on this issue and #Casper's answer shed the light.
Seems to me that the key is to pass the body value as JSON string, which is not written in most of the documentations I found.
Here's another example using httpclient
require 'json'
body = { 'items': [{ 'type': 'type1', 'item_id': 'item1' }]}
HTTPClient.new.delete('http://api.com/endpoint_path/rest_resource', body.to_json)

Why am I getting a 405 on a POST request for JSON?

So I've got a Padrino app with a controller that looks roughly like this (simplified for brevity):
App.controllers :questions do
get :index, :with => :id, :provides => [:html, :json] do
# Stuff
end
post :index, :with => :id, :provides => [:html, :json] do
# Other stuff
end
end
If I hit "questions/1" in my browser, I see the HTML page for the given question. If I hit "questions/1.json", I see the JSON representation of the question. Exactly like I'd expect.
Now, if I submit a POST request to "questions/1" via a web form, it works. But if I try to send a POST request to "questions/1.json" (signaling that I want the response in JSON format—or at least that's how I thought it worked), I get a 405 Method Not Allowed.
I'm guessing there's something basic I'm misunderstanding here. What am I missing? More importantly, how should I define a route to accept POST requests and provide either HTML or JSON responses?
Well, I'm not really sure why this was happening; but for now I've gotten around the issue by setting the "ACCEPT" header in my POST request to "application/json" instead of tacking ".json" onto the end of the URL (and upon my limited internet research, this may be the preferred approach anyway).

Backbone JS and Ruby on Rails CRUD issue

This looks like an issue to me. Normal way Backbone works is using same URL and GET, POST, PUT and DELETE. But obviously:
1) All but POST methods need an ID either in URL or in request body
2) DELETE request can not contain body or some servers ignore body
So how can you make let's say a Ruby on Rails server app successfully work with Backbone without need to hack Backbone such as model.destroy() needs to have ID in the URL? And, as our RoR developer is telling me, normal way to do routes for PUT is to also have an ID in the URL?
There are 5 routes you need to implement to make use of backbone's default sync behavior. For a resource user, they are:
GET /user/ // Get a list of users
GET /user/:id // Get a single users by id
POST /user/ // Create a new user
PUT /user/:id // Update an existing user by id
DELETE /user/:id // Delete an existing user by id
I'm not very familiar with Ruby on Rails, but glancing at their documentation you could fulfill this specification with something like:
match "/user/" => "users#all", :via => :get
match "/user/:user_id" => "users#one", :via => :get
match "/user/" => "users#create", :via => :post
match "/user/:user_id" => "users#update", :via => :put
match "/user/:user_id" => "users#delete", :via => :delete
You should not have to hack Backbone for it to work with RoR. Backbone is smart enough to know (to a certain extent) what URL and what method it should use.
For example, for the initial fetch of a model, if you set url to '/tasks', it will do a GET request to '/tasks/id'. When you change that model, and call model.save, it will do a PUT request to '/tasks/id'. When you call model.destroy, it will send a DELETE request (with an empty body)
The one thing you do have to consider is the CSRF token. I suggest you include backbone-rails in your Gemfile. It includes some JavaScripts to help with Rails/Backbone integration.

RestClient multipart upload from IO

I am trying to upload data as multipart using RestClient like so:
response = RestClient.post(url, io, {
:cookies => {
'JSESSIONID' => #sessionid
},
:multipart => true,
:content_type => 'multipart/form-data'
})
The io argument is a StringIO that contains my file, so it's from memory instead of from the disk.
The server (Tomcat servlet) is unable to read the multipart data, giving an error:
org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
So I believe that RestClient is not sending it in multipart format? Anyone see the problem? I am assuming the problem is on the Ruby (client) side, but I can post my servlet (Spring) code if anyone thinks it might be a server-side problem.
I also wonder what RestClient would use for the uploaded filename, since there isn't an actual file... Can you have a multipart request without a filename?
You can do this, it simply requires subclassing StringIO and adding a non-nil path method to it:
class MailIO < StringIO
def path
'message'
end
end
I've just checked this, and the Mailgun api is pretty down with this.
After consulting with the author of the rest-client library (Archiloque), it seems that if this is possible, the API is not set up to handle it easily. Using the :multipart => true parameter will cause the IO to be treated like a file, and it looks for a non-nil #path on the IO, which for a StringIO is always nil.
If anyone needs this in the future, you'll need to consult with the library's mailing list (code#archiloque.net), as the author seems to think it is possible but perhaps not straightforward.
It CAN easily do streaming uploads from an IO as long as it's not multipart format, which is what I ended up settling for.

Resources