Sending json post request in thirdparty api from sketchup, no results are returned when the code is run for the first time

Hello!
I am trying to send a post request from sketchup to the api and get the returned data. But no result is returned when the code is run for the first time. Clicking run again, the result will be printed.
Here is the gif:
gif 00_00_00-00_00_30~1

And the code:

mod = Sketchup.active_model # Open model
ent = mod.entities # All entities in model
sel = mod.selection # Current selection
@request = Sketchup::Http::Request.new("http://47.118.66.107:5906/solarPV/Arrange", Sketchup::Http::POST)
json_text ='{
  "coordinatePointNum":4,
  "obstaclePointNum":0,
  "coordinate":[[0,0,0],[10,0,0],[10,10,10],[0,10,10]],
  "obstacleNumnum":1,
  "obstacle":[[2,2,2],[8,8,8],[4,7,7]],
  "obstacleNum":[3]
}'
@request.headers= { 'Content-Type' => 'application/json' }
@request.body = json_text
@request.start do |request, response|
  @response=JSON.parse(response.body)  
end
puts @response

Thanks!

http requests are asynchronous. You’ll need to change the structure of your code to something like the following.

mod = Sketchup.active_model # Open model
ent = mod.entities # All entities in model
sel = mod.selection # Current selection
@response = nil

@request = Sketchup::Http::Request.new("http://47.118.66.107:5906/solarPV/Arrange", Sketchup::Http::POST)
json_text ='{
  "coordinatePointNum":4,
  "obstaclePointNum":0,
  "coordinate":[[0,0,0],[10,0,0],[10,10,10],[0,10,10]],
  "obstacleNumnum":1,
  "obstacle":[[2,2,2],[8,8,8],[4,7,7]],
  "obstacleNum":[3]
}'
@request.headers= { 'Content-Type' => 'application/json' }
@request.body = json_text
@request.start do |request, response|
  @response=JSON.parse(response.body)  
  p 'This code is executed after the http response arrives'
  puts @response
end

p 'This code is executed before the http response arrives'
puts @response

Thanks! but If I process the returned data before the “end” character, the web server will shut down due to too much calculation.

@request.start do |request, response|
 @response=JSON.parse(response.body)  
 puts @response
 ...
 ...
end

Then there is an issue on the server side.

Thank you!I am not very good at requesting in thirdparty api. If I want to process the returned data, what should the correct code structure be? I would appreciate it if you give a case!

I got an empty response body, and a FAILED status with error code 0.

You send the request by typing Testing.post in the console.

module Testing

  extend self

  # Tell Ruby to load standard libraries:
  require 'uri'

  @data = Hash[
    "coordinatePointNum" , 4,
    "obstaclePointNum" , 0,
    "coordinate" , [[0,0,0],[10,0,0],[10,10,10],[0,10,10]],
    "obstacleNumnum" , 1,
    "obstacle" , [[2,2,2],[8,8,8],[4,7,7]],
    "obstacleNum" , [3]
  ]

  @verbose = true

  def cancel
    @request.cancel
  end

  def clear
    @request  = nil
    @response = nil
  end

  def data
    puts @data.inspect
  end

  def data=(obj)
    @data = obj
  end

  # Return the response body.
  # @return [String] for text, HTML or unknown data type.
  # @return [Hash] for JSON or multipart form data.
  def get_response_body
    return 'The response reference is unset!' unless @response
    #
    case get_response_type()
    when 'application/json;'
      if @response.body.empty?
        'The response body was empty! JSON cannot parse empty string.'
      else
        JSON.parse(@response.body)
      end
    when 'multipart/form-data;'
      URI.decode_www_form(@response.body).to_h
    when 'text/html;'
      @response.body
    else
      @response.body
    end
    #
  rescue JSON::ParserError => e
    e.set_backtrace(e.backtrace.drop(1))
    e.inspect
  rescue => e
    e.inspect
  end

  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses
  def get_response_code
    code = @response.status_code
    return "Request Successful (#{code})" if code.between?(200,299)
    case code
    when 302
      '302 Authentication Failure: Must Re-login'
    when 400
      "400 Bad Request"
    when 401
      '401 Unauthorized: Must Re-login'
    when 403
      '403 Forbidden'
    when 405
      '405 Method Not Allowed'
    when 406
      '406 Not Acceptable'
    when 408
      '408 Request Timeout'
    when 415
      '415 Unsupported Media Type'
    when 418
      "418 I'm a teapot"
    when 429
      '429 Too Many Requests'
    when 503
      '503 Server Unavailable'
    else
      if code.between?(500,599)
        "#{code} Server Error"
      elsif code.between?(400,499)
        "#{code} Client Error"
      else
        "#{code} HTTP Error"
      end
    end
  end

  # Return the content type of the response.
  # @return [String]
  def get_response_type
    return 'The response reference is unset!' unless @response
    #
    headers = @response.headers rescue {} # returns hash of the headers
    type_str = headers['Content-Type'] rescue nil
    return 'unknown' if !type_str
    type_str.split.first rescue ''
    #
  rescue => e
    e.inspect
  end

  def json
    puts @data.to_json.inspect
  end

  def post(arg = :json)
    #
    clear() # reset @request and @response
    #
    @request = Sketchup::Http::Request.new(
      "http://47.118.66.107:5906/solarPV/Arrange",
      Sketchup::Http::POST
    )
    # Common headers:
    headers = {
      'Accept-Encoding' => 'identity, *;q=0' # don't compress
    }
    # Set 'Content-Type', body content and acceptable responses:
    if arg == :json
      headers['Content-Type']= 'application/json'
      accept = 'multipart/form-data;q=0.7,text/html;q=0.5'
      headers['Accept']= accept.prepend('application/json,')
      @request.body = @data.to_json
    elsif arg == :form
      headers['Content-Type']= 'multipart/form-data'
      accept = 'application/json;q=0.7,text/html;q=0.5'
      headers['Accept']= accept.prepend('multipart/form-data,')
      @request.body = URI.encode_www_form(@data)
    elsif arg == :text
      headers['Content-Type']= 'text/html'
      accept = 'multipart/form-data;q=0.7,application/json;q=0.5'
      headers['Accept']= accept.prepend('text/html,')
      @request.body = @data.to_s
    else
      fail(ArgumentError,"Unknown argument: #{arg.inspect}",caller)
    end
    #
    @request.headers= headers
    # The start method always immediately returns true.
    @request.start do |request, response|
      puts "HTTP response received."
      @response = response
      if @verbose
        puts "Raw response is:"
        puts @response.body.inspect
      end
      result = status()
      puts "Post response HTTP request status: #{result}"
      puts get_response_code() if result == 'FAILED' || result == 'UNKNOWN'
      puts
    end
    puts "HTTP request sent ..."
    puts "Pre response HTTP request status: #{status()}\n"
    #
  end

  def status
    case @request.status
    when Sketchup::Http::STATUS_UNKNOWN  then 'UNKNOWN'
    when Sketchup::Http::STATUS_SUCCESS  then 'SUCCESS'
    when Sketchup::Http::STATUS_PENDING  then 'PENDING'
    when Sketchup::Http::STATUS_CANCELED then 'CANCELED'
    when Sketchup::Http::STATUS_FAILED   then 'FAILED'
    else 
      'UNKNOWN'
    end
  end

  def terse
    @verbose = false
  end

  def verbose(arg = true)
    @verbose = arg ? true : false
  end


  # Init the module:
  clear()

end

Thank you Dan. The reason why you did not get the return data is that the server is shut down, and it can be used normally now.

Or you can use a tool like Postman to quickly test a connection and inspect return values.

1 Like

Does Postman run inside SketchUp’s Ruby ?

No, it is an external tool. But it should help you to quickly see if the api you are calling behaves as expected.

2 Likes

+1 to using tools like Postman (https://www.postman.com/) to test HTTP APIs, learning how they behave and inspect data.

Another useful tool is Fiddler, that will allow you to inspect outgoing and incoming HTTP traffic so you can verify that you send and receive is really what you expect: Fiddler Classic | Original Web Capturing Tool for Windows

1 Like