5

I am trying to create a rest-client request in Ruby for the API request that is triggered in this page. (source)

From looking at the Javascript in the page, I noticed that there is a Javascript Blob being created and the JSON content appended to that and then submitted in a multipart form with the following script -

I tried to emulate this with the rest-client gem in ruby with the following code -

namespace :materialize do
  task :connect => :environment do
    base_uri = "https://imatsandbox.materialise.net/web-api/cartitems/register"
    request = '{
     "cartItems":[
     {
       "toolID":"d65e1eca-7adf-453d-a3bb-eb051fffb567",
       "MyCartItemReference":"some reference",
       "modelID":"62352bab-d490-410c-851d-bc62e056e82a",
       "modelFileName":"",
       "fileUnits":"mm",
       "fileScaleFactor":"1",
       "materialID":"035f4772-da8a-400b-8be4-2dd344b28ddb",
       "finishID":"bba2bebb-8895-4049-aeb0-ab651cee2597",
       "quantity":"1",
       "xDimMm":"12",
       "yDimMm":"159.94",
       "zDimMm":"12",
       "volumeCm3":"2.0",
       "surfaceCm2":"100.0",
       "iMatAPIPrice": "25.0",
       "mySalesPrice": "26.0",
     }
     ],
     "currency":"EUR"
  }'
File.open('request', 'wb') do |f|
    f.write request
end


  response = RestClient.post base_uri, {:data => request, headers: {:multipart => true, accept: :json}}
  puts response.request
 end
end

The response body I always get -

"{\"error\":{\"message\":\"Wrong request body. Check if all parameters set correctly\",\"code\":401},\"cartItems\":[]}"

What am I doing wrong?

Michael Victor
  • 861
  • 2
  • 18
  • 42
  • maybe if we see how your server `log` is making this `api` request we can figure out what you are doing wrong thanks – Fabrizio Bertoglio Aug 12 '17 at 07:52
  • Sure, I will get that for you today. – Michael Victor Aug 13 '17 at 06:47
  • this is the response I get from your source page https://imatsandbox.materialise.net/api/demo/cart-item-creation-api.html I get a 404. To help you I need to see this response [![enter image description here](https://i.stack.imgur.com/t4nOx.png)](https://i.stack.imgur.com/t4nOx.png) – Fabrizio Bertoglio Aug 11 '17 at 07:31

3 Answers3

2

You're getting a 401, which means your request is not authorized. I think you need to pass credentials with your request. Check the note at bottom of page about passing your registered email address to the demo api: https://imatsandbox.materialise.net/api/demo/

Looks like you need to do this:

https://i.materialise.com/web-api/materials?user=<your registered email address here>
Ken Hill
  • 156
  • 5
2

To submit a mixed data of json and blob you need to use mulpipart.

RestClient already has Multipart Implementation

And your solution will look following:

require 'rest-client'

url = 'https://imatsandbox.materialise.net/web-api/cartitems/register'
json = '{
  "cartItems":[
    {
      "toolID":"d65e1eca-7adf-453d-a3bb-eb051fffb567",
      "MyCartItemReference":"some reference",
      "modelID":"62352bab-d490-410c-851d-bc62e056e82a",
      "modelFileName":"",
      "fileUnits":"mm",
      "fileScaleFactor":"1",
      "materialID":"035f4772-da8a-400b-8be4-2dd344b28ddb",
      "finishID":"bba2bebb-8895-4049-aeb0-ab651cee2597",
      "quantity":"1",
      "xDimMm":"12",
      "yDimMm":"159.94",
      "zDimMm":"12",
      "volumeCm3":"2.0",
      "surfaceCm2":"100.0",
      "iMatAPIPrice": "25.0",
      "mySalesPrice": "26.0",
    }
  ],
  "currency":"EUR"
}'

def stringfile(string, filename="file_#{rand 100000}", type=MIME::Types.type_for("json").first.content_type)
  file = StringIO.new(string)

  file.instance_variable_set(:@path, filename)
  def file.path
    @path
  end
  file.instance_variable_set(:@type, type)
  def file.content_type
    @type
  end

  return file
end

response = RestClient.post url,
  data: stringfile(json),
  file: [
    File.new("./1.png", 'rb')
  ]


puts response.body

Result of response.body is:

{
 "currency": "EUR",
  "cartItems": [
    {
      "myCartItemReference": "some reference",
      "cartItemID": "97884fef-d2ae-45e4-a18c-b52b3dcdcb9d",
      "toolID": "d65e1eca-7adf-453d-a3bb-eb051fffb567",
      "modelID": "c65278da-8693-4f49-a5c0-8be55a3e63b2",
      "modelFileName": "The_Club_7plus.obj",
      "fileUnits": "mm",
      "fileScaleFactor": 1.0,
      "materialID": "035f4772-da8a-400b-8be4-2dd344b28ddb",
      "materialName": "Polyamide",
      "finishID": "bba2bebb-8895-4049-aeb0-ab651cee2597",
      "finishName": "Natural-White-Polyamide",
      "quantity": 1,
      "xDimMm": 81.2660000000,
      "yDimMm": 159.9350000000,
      "zDimMm": 10.0960000000,
      "volumeCm3": 15.5864000000,
      "surfaceCm2": 260.2880000000,
      "iMatAPIPrice": 25.0,
      "mySalesPrice": 26.0,
      "mySalesUnitPrice": 26.0,
      "iMatPrice": 13.61,
      "validUntil": "2017-09-04T00:00:00+02:00"
    }
  ]
}

I hope it helped you ;)

itsnikolay
  • 17,415
  • 4
  • 65
  • 64
  • I tried copy pasting the code above into a rake task and I still get the following error :/ `{"error":{"message":"Wrong request body. Check if all parameters set correctly","code":401},"cartItems":[]}` How did you run the above code that it worked for you? – Michael Victor Aug 20 '17 at 18:30
  • @MichaelVictor I created `test.rb` file with content I pasted and run it `ruby test.rb`, that is. – itsnikolay Aug 20 '17 at 18:35
  • @MichaelVictor now I'm getting an error, let me check – itsnikolay Aug 20 '17 at 18:37
  • Perhaps try with this new model ID - `62352bab-d490-410c-851d-bc62e056e82a` ? – Michael Victor Aug 20 '17 at 18:46
  • @MichaelVictor we need a little hack to bring json to `File` type. I added `stringfile` method for it, to make a fake file in ruby. That's because `RectClient` works with `Files` only in multipart mode. Code changed. – itsnikolay Aug 20 '17 at 18:59
  • 1
    It works, this was a very interesting problem for me, and I learnt a lot, thanks! I hope it was interesting for you too! – Michael Victor Aug 20 '17 at 19:02
  • @MichaelVictor thanks for bounty! I was really interesting I also learnt some interesting things. – itsnikolay Aug 20 '17 at 19:05
0

I also get 401 sometimes when I use RestClient.post, I solve by using the Resource.new

res = RestClient::Resource.new("http://www.sample.com/some.json",:headers => {'Content-Type' => "application/json"})

res.post(json_data)
Roshan
  • 905
  • 9
  • 21