I am getting error 400 on automating POST API with file upload(string($binary))ad(

[I am getting error 400 on automating POST API with file upload(string($binary))

I have copied the request header, can anyone help to give the basic syntax for post request with file upload

*** Settings ***
Library     RequestsLibrary
Library     OperatingSystem
Library     JSONLibrary
Library     ../../resources/scripts/disable_warnings.py

*** Variables ***
${SESSION}          https:/...
${HEADER_TEXT}    ...

*** Keywords ***
Create Session
  disable_warnings.Disable Warnings
  RequestsLibrary.Create Session    s1services   ${SESSION}
  ${header}=  Create Dictionary  Content-Type=application/json  s1code=${HEADER_TEXT}  verify=True
  Set Suite Variable  ${HEADERS_HEADER}  ${header}

I Send The Request
  [Arguments]  ${json_file}  ${json_endpoint}
  ${json}  Get File  ${json_file}${/}
  ${response}  RequestsLibrary.POST On Session  s1services  ${json_endpoint}  data=${json.encode('utf-8')} headers=${HEADERS_HEADER}
  ${data}=  Evaluate  json.loads(r'''${response.text}''', strict=False)  json
  set suite variable  ${RESPONSE_DATA}  ${data}

This is the disable_warnings.py

import urllib3


    def disable_warnings():
        urllib3.disable_warnings()

Hi Ann,

The payload tab from your dev tools is more important as that will tell you what format the file needs to be sent as

From the headers, things you’ll want to pay attention to are:

  • content-type, in your case multipart/form-data, also pay attention to that boundary value, does that string need to be different every time? is it an encoded value or just a random number (something to check with your dev team)
  • cookies, I don’t see any of the ones that are commonly needed, but you may need to replicate some of these e.g. username-local-888* might be important?
  • sec-* some applications won’t work if you don’t send these headers correctly, some don’t car if you don’t send them

When you select the paylod tab look for an option like raw data (by default it’s probably parsed into key value pairs, as you have a content-type of multipart/form-data, I would expect a single line string that looks something like Payload=TGMS&Bound=North&File=<some sort of binary string>

Dave.

I tried to use the below script and still I am getting errors. I dont know how to pass Payload=TGMS&Bound=North&File=

Please help

Post Inspection data
Create Session My Session ${base_url}
&{file_data} = Create Dictionary file=@TunnelFOX_API/SampleDataFromTGMS_Aug22.csv;type=text/csv
&{headers} = Create Dictionary accept=/ Content-Type=multipart/form-data
&{data} = Create Dictionary Line=blue Subsystem=runningrail Payload=TGMS Bound=north
${response} = POST On Session My Session /api/InspectionData files=${file_data} data=${data} headers=${headers}
Should Be Equal As Strings ${response.status_code} 200
Log Response: ${response.text}
Delete All Sessions`

Hi Ann,

These 2 lines

&{data}=    Create Dictionary    Line=blue    Subsystem=runningrail    Payload=TGMS    Bound=north
${response}=    POST On Session    My Session    /api/InspectionData    files=${file_data}    data=${data} 

should be sending a request payload/body of

Line=blue&Subsystem=runningrail&Payload=TGMS&Bound=north

Which is quite different to your payload/body of

Payload=TGMS&Bound=North&File=

Try changing these 2 lines to this for now:

&{data}=    Create Dictionary    Payload=TGMS    Bound=north    File=${EMPTY}
${response}=    POST On Session    My Session    /api/InspectionData    data=${data} 

This should send the request with no file, hopefully it will either give you a 200 OK or an error saying something like missing file.

To be able to help you with sending the file, I need to see what the file data looks like, I don’t need to see all of it just the first 50 characters and the last 50 characters will hopefully be enough to get a sense of the encoding type.

Note: in your case I expect you won’t be able to use the files kwarg as you Content-Type is multipart/form-data and not the mime type for a file.

Dave.

I got the solution,

If its helpful for any one i am posting the working code.

Send POST Request
${url} = Set Variable http://localhost:8080/api/InspectionData

${session} =    Create Session    My Session    ${url}

${payload} =    Create Dictionary   Line=xxx   Subsystem=xxxx  Payload=xxx  Bound=xxx

${file_name} =    Set Variable    SampleDataFromTGMS_Aug22.csv

${file_path} =    Set Variable    ../Resources/${file_name}
${headers} =    Create Dictionary    accept=*/*

${data}=  Evaluate  {'File': ("${file_name}", open("${file_path}", 'r+b'), 'text/csv')}

${response} =    POST On Session    My Session    ${url}   data=${payload}   files=${data}   headers=${headers}
Should Be Equal As Strings    ${response.status_code}    200

Log    Response: ${response.text}
Delete All Sessions
3 Likes

Awesome, this piece of code helped to upload an XSLX file in multipart/form-data where I needed to set content-type in body as application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

Just wondering, if there is any native way to do in Robot Framework using Get File For Streaming Upload? rather than python code?

Prepare a file for upload via form data
    [Arguments]    ${content_type}    ${file_path}
    ${data}=  Evaluate  {'File': (os.path.basename("${file_path}"), open("${file_path}", 'r+b'), "${content_type}")}
    Set Suite Variable    ${FORM_DATA_PREPARED}    ${data}