Robotframework.request - How to make a POST request with content “multipart/form-data”












1















I want to make a POST request in Robot Framework with "Content-Type: multipart/form-data" using the RequestsLibrary but nothing seems to work.
The Keyword that makes this request looks as follows:



*** Variables ***
&{API_CREDS} username=myusername password=mypwd

*** Keywords ***
Get token
# Assumes that session has been created
[Arguments] ${Session_id}
&{headers}= create dictionary Content-Type=multipart/form-data
${response}= Post Request ${Session_id} ${AUTH_TOKEN_URL_PATH} data=${API_CREDS} headers=${headers}
should be equal as integers ${response.status_code} 200
[Return] ${response.json()['token']}


But the POST request that is actually sent does not contain a "Content-Type" header and the body is just a raw data={'username' = 'myusername', ' password' = 'mypwd'}



I have tried many things that I have found searching around but nothing works. Does the RequestsLibrary of Robot Framework actually supports sending a POST request with "Content-Type: multipart/form-data"?, if so how is this done?



PS: I am using Robot Framework on Windows 10 with Python 3.7.1.
The POST request is actually sent, but it does not contain a Content-Type header, nor a form-data payload, as mentioned above.










share|improve this question





























    1















    I want to make a POST request in Robot Framework with "Content-Type: multipart/form-data" using the RequestsLibrary but nothing seems to work.
    The Keyword that makes this request looks as follows:



    *** Variables ***
    &{API_CREDS} username=myusername password=mypwd

    *** Keywords ***
    Get token
    # Assumes that session has been created
    [Arguments] ${Session_id}
    &{headers}= create dictionary Content-Type=multipart/form-data
    ${response}= Post Request ${Session_id} ${AUTH_TOKEN_URL_PATH} data=${API_CREDS} headers=${headers}
    should be equal as integers ${response.status_code} 200
    [Return] ${response.json()['token']}


    But the POST request that is actually sent does not contain a "Content-Type" header and the body is just a raw data={'username' = 'myusername', ' password' = 'mypwd'}



    I have tried many things that I have found searching around but nothing works. Does the RequestsLibrary of Robot Framework actually supports sending a POST request with "Content-Type: multipart/form-data"?, if so how is this done?



    PS: I am using Robot Framework on Windows 10 with Python 3.7.1.
    The POST request is actually sent, but it does not contain a Content-Type header, nor a form-data payload, as mentioned above.










    share|improve this question



























      1












      1








      1


      1






      I want to make a POST request in Robot Framework with "Content-Type: multipart/form-data" using the RequestsLibrary but nothing seems to work.
      The Keyword that makes this request looks as follows:



      *** Variables ***
      &{API_CREDS} username=myusername password=mypwd

      *** Keywords ***
      Get token
      # Assumes that session has been created
      [Arguments] ${Session_id}
      &{headers}= create dictionary Content-Type=multipart/form-data
      ${response}= Post Request ${Session_id} ${AUTH_TOKEN_URL_PATH} data=${API_CREDS} headers=${headers}
      should be equal as integers ${response.status_code} 200
      [Return] ${response.json()['token']}


      But the POST request that is actually sent does not contain a "Content-Type" header and the body is just a raw data={'username' = 'myusername', ' password' = 'mypwd'}



      I have tried many things that I have found searching around but nothing works. Does the RequestsLibrary of Robot Framework actually supports sending a POST request with "Content-Type: multipart/form-data"?, if so how is this done?



      PS: I am using Robot Framework on Windows 10 with Python 3.7.1.
      The POST request is actually sent, but it does not contain a Content-Type header, nor a form-data payload, as mentioned above.










      share|improve this question
















      I want to make a POST request in Robot Framework with "Content-Type: multipart/form-data" using the RequestsLibrary but nothing seems to work.
      The Keyword that makes this request looks as follows:



      *** Variables ***
      &{API_CREDS} username=myusername password=mypwd

      *** Keywords ***
      Get token
      # Assumes that session has been created
      [Arguments] ${Session_id}
      &{headers}= create dictionary Content-Type=multipart/form-data
      ${response}= Post Request ${Session_id} ${AUTH_TOKEN_URL_PATH} data=${API_CREDS} headers=${headers}
      should be equal as integers ${response.status_code} 200
      [Return] ${response.json()['token']}


      But the POST request that is actually sent does not contain a "Content-Type" header and the body is just a raw data={'username' = 'myusername', ' password' = 'mypwd'}



      I have tried many things that I have found searching around but nothing works. Does the RequestsLibrary of Robot Framework actually supports sending a POST request with "Content-Type: multipart/form-data"?, if so how is this done?



      PS: I am using Robot Framework on Windows 10 with Python 3.7.1.
      The POST request is actually sent, but it does not contain a Content-Type header, nor a form-data payload, as mentioned above.







      python python-requests robotframework






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 26 '18 at 8:46









      Al Imran

      671416




      671416










      asked Nov 24 '18 at 22:37









      juan noguerajuan noguera

      45126




      45126
























          1 Answer
          1






          active

          oldest

          votes


















          3














          The underlying python library that's used - requests , has some peculiarities working with multipart "form-data" content. It uses it primary for sending files as part of the request (an upload functionality); roughly speaking when it parsed your arguments, it stripped the header because there were no files to be sent. Also, if it didn't do that, it's not designed to deduct what are the different parts in your multipart payload - e.g. it doesn't automatically put every key-value pair in a separate part.



          To overcome this, one usually uses the files parameter, passing as argument the content of the different parts. In doing so, the requests library will automatically set the form-data header, and break-up the content in parts.

          Here's how to do that in RF, explanation follows:



          ${data}=    Evaluate    {'username': (None, 'myusername'), 'password': (None, 'mypwd')}
          ${response}= Post Request ${Session_id} ${AUTH_TOKEN_URL_PATH} files=${data}


          Using the files parameter in the Post Request keyword your payload will be passed to the requests post method as is. You don't need to set the headers explicitly, the library will do it for you.



          What is passed as argument is a dictionary, were the values are the parts' content. As you can see the actual values are python tuples, because you want to override the filename in the part. This is better explained with an example; if the data is like this, the value being a simple sting:



          ${data}=    Evaluate    {'username': 'myusername', 'password': 'mypwd'}


          , then the payload will turn up as:



          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="username"; filename="username"

          myusername
          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="password"; filename="password"

          mypwd
          --7579227dh785568ha91866339229add786--


          Notice how each part has a "filename" property, equal to the parameter name.



          When the value is a tuple, its first member sets the "filename" property of the part; and when it is a None, there is no "filename" at all, producing this result:



          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="username"

          myusername
          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="password"

          mypwd
          --7579227dh785568ha91866339229add786--


          , which is probably your goal.






          share|improve this answer


























          • Thanks a lot Todor. The RequestsLibrary needs some work on documentation, so I was checking the actual python implementation when I got your comprehensive valid answer.

            – juan noguera
            Nov 25 '18 at 13:25











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53462955%2frobotframework-request-how-to-make-a-post-request-with-content-multipart-form%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          3














          The underlying python library that's used - requests , has some peculiarities working with multipart "form-data" content. It uses it primary for sending files as part of the request (an upload functionality); roughly speaking when it parsed your arguments, it stripped the header because there were no files to be sent. Also, if it didn't do that, it's not designed to deduct what are the different parts in your multipart payload - e.g. it doesn't automatically put every key-value pair in a separate part.



          To overcome this, one usually uses the files parameter, passing as argument the content of the different parts. In doing so, the requests library will automatically set the form-data header, and break-up the content in parts.

          Here's how to do that in RF, explanation follows:



          ${data}=    Evaluate    {'username': (None, 'myusername'), 'password': (None, 'mypwd')}
          ${response}= Post Request ${Session_id} ${AUTH_TOKEN_URL_PATH} files=${data}


          Using the files parameter in the Post Request keyword your payload will be passed to the requests post method as is. You don't need to set the headers explicitly, the library will do it for you.



          What is passed as argument is a dictionary, were the values are the parts' content. As you can see the actual values are python tuples, because you want to override the filename in the part. This is better explained with an example; if the data is like this, the value being a simple sting:



          ${data}=    Evaluate    {'username': 'myusername', 'password': 'mypwd'}


          , then the payload will turn up as:



          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="username"; filename="username"

          myusername
          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="password"; filename="password"

          mypwd
          --7579227dh785568ha91866339229add786--


          Notice how each part has a "filename" property, equal to the parameter name.



          When the value is a tuple, its first member sets the "filename" property of the part; and when it is a None, there is no "filename" at all, producing this result:



          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="username"

          myusername
          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="password"

          mypwd
          --7579227dh785568ha91866339229add786--


          , which is probably your goal.






          share|improve this answer


























          • Thanks a lot Todor. The RequestsLibrary needs some work on documentation, so I was checking the actual python implementation when I got your comprehensive valid answer.

            – juan noguera
            Nov 25 '18 at 13:25
















          3














          The underlying python library that's used - requests , has some peculiarities working with multipart "form-data" content. It uses it primary for sending files as part of the request (an upload functionality); roughly speaking when it parsed your arguments, it stripped the header because there were no files to be sent. Also, if it didn't do that, it's not designed to deduct what are the different parts in your multipart payload - e.g. it doesn't automatically put every key-value pair in a separate part.



          To overcome this, one usually uses the files parameter, passing as argument the content of the different parts. In doing so, the requests library will automatically set the form-data header, and break-up the content in parts.

          Here's how to do that in RF, explanation follows:



          ${data}=    Evaluate    {'username': (None, 'myusername'), 'password': (None, 'mypwd')}
          ${response}= Post Request ${Session_id} ${AUTH_TOKEN_URL_PATH} files=${data}


          Using the files parameter in the Post Request keyword your payload will be passed to the requests post method as is. You don't need to set the headers explicitly, the library will do it for you.



          What is passed as argument is a dictionary, were the values are the parts' content. As you can see the actual values are python tuples, because you want to override the filename in the part. This is better explained with an example; if the data is like this, the value being a simple sting:



          ${data}=    Evaluate    {'username': 'myusername', 'password': 'mypwd'}


          , then the payload will turn up as:



          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="username"; filename="username"

          myusername
          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="password"; filename="password"

          mypwd
          --7579227dh785568ha91866339229add786--


          Notice how each part has a "filename" property, equal to the parameter name.



          When the value is a tuple, its first member sets the "filename" property of the part; and when it is a None, there is no "filename" at all, producing this result:



          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="username"

          myusername
          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="password"

          mypwd
          --7579227dh785568ha91866339229add786--


          , which is probably your goal.






          share|improve this answer


























          • Thanks a lot Todor. The RequestsLibrary needs some work on documentation, so I was checking the actual python implementation when I got your comprehensive valid answer.

            – juan noguera
            Nov 25 '18 at 13:25














          3












          3








          3







          The underlying python library that's used - requests , has some peculiarities working with multipart "form-data" content. It uses it primary for sending files as part of the request (an upload functionality); roughly speaking when it parsed your arguments, it stripped the header because there were no files to be sent. Also, if it didn't do that, it's not designed to deduct what are the different parts in your multipart payload - e.g. it doesn't automatically put every key-value pair in a separate part.



          To overcome this, one usually uses the files parameter, passing as argument the content of the different parts. In doing so, the requests library will automatically set the form-data header, and break-up the content in parts.

          Here's how to do that in RF, explanation follows:



          ${data}=    Evaluate    {'username': (None, 'myusername'), 'password': (None, 'mypwd')}
          ${response}= Post Request ${Session_id} ${AUTH_TOKEN_URL_PATH} files=${data}


          Using the files parameter in the Post Request keyword your payload will be passed to the requests post method as is. You don't need to set the headers explicitly, the library will do it for you.



          What is passed as argument is a dictionary, were the values are the parts' content. As you can see the actual values are python tuples, because you want to override the filename in the part. This is better explained with an example; if the data is like this, the value being a simple sting:



          ${data}=    Evaluate    {'username': 'myusername', 'password': 'mypwd'}


          , then the payload will turn up as:



          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="username"; filename="username"

          myusername
          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="password"; filename="password"

          mypwd
          --7579227dh785568ha91866339229add786--


          Notice how each part has a "filename" property, equal to the parameter name.



          When the value is a tuple, its first member sets the "filename" property of the part; and when it is a None, there is no "filename" at all, producing this result:



          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="username"

          myusername
          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="password"

          mypwd
          --7579227dh785568ha91866339229add786--


          , which is probably your goal.






          share|improve this answer















          The underlying python library that's used - requests , has some peculiarities working with multipart "form-data" content. It uses it primary for sending files as part of the request (an upload functionality); roughly speaking when it parsed your arguments, it stripped the header because there were no files to be sent. Also, if it didn't do that, it's not designed to deduct what are the different parts in your multipart payload - e.g. it doesn't automatically put every key-value pair in a separate part.



          To overcome this, one usually uses the files parameter, passing as argument the content of the different parts. In doing so, the requests library will automatically set the form-data header, and break-up the content in parts.

          Here's how to do that in RF, explanation follows:



          ${data}=    Evaluate    {'username': (None, 'myusername'), 'password': (None, 'mypwd')}
          ${response}= Post Request ${Session_id} ${AUTH_TOKEN_URL_PATH} files=${data}


          Using the files parameter in the Post Request keyword your payload will be passed to the requests post method as is. You don't need to set the headers explicitly, the library will do it for you.



          What is passed as argument is a dictionary, were the values are the parts' content. As you can see the actual values are python tuples, because you want to override the filename in the part. This is better explained with an example; if the data is like this, the value being a simple sting:



          ${data}=    Evaluate    {'username': 'myusername', 'password': 'mypwd'}


          , then the payload will turn up as:



          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="username"; filename="username"

          myusername
          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="password"; filename="password"

          mypwd
          --7579227dh785568ha91866339229add786--


          Notice how each part has a "filename" property, equal to the parameter name.



          When the value is a tuple, its first member sets the "filename" property of the part; and when it is a None, there is no "filename" at all, producing this result:



          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="username"

          myusername
          --7579227dh785568ha91866339229add786
          Content-Disposition: form-data; name="password"

          mypwd
          --7579227dh785568ha91866339229add786--


          , which is probably your goal.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 25 '18 at 10:55

























          answered Nov 25 '18 at 10:49









          Todor MinakovTodor Minakov

          6,23112136




          6,23112136













          • Thanks a lot Todor. The RequestsLibrary needs some work on documentation, so I was checking the actual python implementation when I got your comprehensive valid answer.

            – juan noguera
            Nov 25 '18 at 13:25



















          • Thanks a lot Todor. The RequestsLibrary needs some work on documentation, so I was checking the actual python implementation when I got your comprehensive valid answer.

            – juan noguera
            Nov 25 '18 at 13:25

















          Thanks a lot Todor. The RequestsLibrary needs some work on documentation, so I was checking the actual python implementation when I got your comprehensive valid answer.

          – juan noguera
          Nov 25 '18 at 13:25





          Thanks a lot Todor. The RequestsLibrary needs some work on documentation, so I was checking the actual python implementation when I got your comprehensive valid answer.

          – juan noguera
          Nov 25 '18 at 13:25


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53462955%2frobotframework-request-how-to-make-a-post-request-with-content-multipart-form%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

          Calculate evaluation metrics using cross_val_predict sklearn

          Insert data from modal to MySQL (multiple modal on website)