How to send a request with form-data

I recently tried to send a request with an image using the sketchup api, but I couldn’t find the information about how to set the body.My body information and headers information are as follows:

headers = {"Content-Type"=>"multipart/form-data", "Authorization"=>auth_token}
payload = {
            "image" => File.open(image),
          }.to_json

I tried another:

headers = {"Content-Type"=>"multipart/form-data", "Authorization"=>auth_token}
payload = [ ["image", File.open(image)] ].to_json

But it seems that none of them can.
Similarly, I have tried to use Ruby’s own http, but most of the time sketchup fails to respond and send requests.

Well firstly, File.open doesn’t do anything but open the file and return a reference to the file object. In other words it does not actually read the file data.

Secondly, raster image files are binary format so you’d probably need to pass a "rb" (read binary) mode parameter to the File method that is used.

Also, keep in mind that the File class is a subclass of IO and inherits many methods for it’s superclass. You could instead just use IO::binread which ensures that the file is closed after the read.

The Sketchup::Http::Request#body= setter method is listed for SketchUp’s Sketchup::Http::Request class. So …

begin
  image_data = IO.binread(image_path)
rescue => err
  # handle the error and bailout
else
  @request.body= image_data
end

Note that it is best practice to wrap any file IO operations within a beginrescueend block.

If you are going to use multipart body, you’ll need to insert a boundary and define that boundary (I think in the header.)

The Ruby library Net::Http requests are blocking. This is why SketchUp’s API implemented asynchronous requests.

The Ruby request classes are similar to the File class in that the basic functionality is inherited from the Net::HTTPGenericRequest superclass (ie, this is where the #body= setter is defined.)

2 Likes

In regard to form data, I have used this in the past.

I think that I used the URI class’ form encoding method. Perhaps with both the Ruby lib and SketchUp’s API. (It’s been awhile.)

See the Ruby example: GET with Dynamic Parameters

You’d need to require "uri" before use.

2 Likes

Now, if you wish to use json, then it sould be simpler, but the content type is "application/json"

headers = {"Content-Type"=>"application/json", "Authorization"=>auth_token}
payload = {
            "image" => image_data,
          }.to_json
@request.body= payload

If the response content type is also "application/json" then parse the response body back into a Ruby hash …

@request.start do |request, response|
  headers = response.headers
  type = headers['Content-Type']
  if type == 'application/json'
    @data = JSON.parse(response.body)
  else
    @data = response.body
  end
end

You can have other elsif clause(s) for other content types, of course.

BEWARE: The SketchUp API Http class headers are not case insensitive like the Ruby library classes are. So you must access the API header hashes with exact (correct) case key names.

1 Like

Hi, I am having trouble understanding what you are trying to do.
Are you trying to use an external Rest API to download an image?

Below is an example of how I get a response from Rest API

require 'net/http'
require 'uri'

url = "#{HERE IS WHERE REST API URL GOES}"
uri = URI.parse(url)
request = Net::HTTP::Post.new(uri)
req_options = {
  use_ssl: uri.scheme == 'https'
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end
hash_response = eval(response.body)
json = JSON.parse(hash_response)
# Below is an example if json API has key value of "image"
json["image"]

Again not sure if this is what you are looking for.

1 Like

I finally chose this method. Thank you for your help.

I want to upload pictures. I finally chose to transfer the base64 format. I have solved the problem. Thank you for your attention