asyrjasalo / RESTinstance

Robot Framework library for RESTful JSON APIs
https://pypi.org/project/RESTinstance
GNU Lesser General Public License v3.0
206 stars 84 forks source link

Trouble sending XML in body when using POST #27

Closed MrSteve2 closed 5 years ago

MrSteve2 commented 6 years ago

TL;DR the POST keyword eventually calls request.request using json= parameter for the body. Yet for XML the body is not in JSON format.

Detailed explanation of what I think is root cause along with sample code can be found here

Robot file to recreate issue:

*** Settings ***
Library    REST

*** Variables ***
${SERVER_URL}    https://www.w3schools.com/xml/tempconvert.asmx

*** Test Cases ***
Send XML Body test
    Send SOAP via POST    <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><FahrenheitToCelsius xmlns="https://www.w3schools.com/xml/"><Fahrenheit>100</Fahrenheit></FahrenheitToCelsius></soap:Body></soap:Envelope>

*** Keywords ***
Send SOAP via POST
    [Arguments]         ${body}
    SET HEADERS    {"SOAPAction": "https://www.w3schools.com/xml/FahrenheitToCelsius","Content-Type": "text/xml","Cache-Control": "no-cache"}

    ${resp}=    POST    ${SERVER_URL}    data=${body}
    Log    ${resp}  repr=true

Python code to prove endpoint works with Sample POST:

import requests

url = "https://www.w3schools.com/xml/tempconvert.asmx"

payload = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><FahrenheitToCelsius xmlns="https://www.w3schools.com/xml/"><Fahrenheit>100</Fahrenheit></FahrenheitToCelsius></soap:Body></soap:Envelope>'
headers = {
    'SOAPAction': "\"https://www.w3schools.com/xml/FahrenheitToCelsius\"",
    'Content-Type': "text/xml",
    'Cache-Control': "no-cache",
    }

response = requests.request("POST", url, data=payload, headers=headers)

print(response.text)
MrSteve2 commented 6 years ago

So modifying to use data= instead of json equals in ther requests.request (aka client) call allows me to send xml in the body. See line 474 of https://github.com/asyrjasalo/RESTinstance/blob/master/src/REST/keywords.py So change:


            response = client(request['method'], request['url'],
                              params=request['query'],
                              json=request['body'],
                              headers=request['headers'],
                              proxies=request['proxies'],
                              cert=request['cert'],
                              timeout=tuple(request['timeout']),
                              allow_redirects=request['allowRedirects'],
                              verify=request['sslVerify'])```
To:
```       try:
            response = client(request['method'], request['url'],
                              params=request['query'],
                              data=request['body'],
                              headers=request['headers'],
                              proxies=request['proxies'],
                              cert=request['cert'],
                              timeout=tuple(request['timeout']),
                              allow_redirects=request['allowRedirects'],
                              verify=request['sslVerify'])```

Of course that breaks the JSON functionality :)

Now just need to find time to figure right way to specify parameters to POST,
ideally we would use json= instead of body=
Then use data= to handle xml et al
asyrjasalo commented 5 years ago

This is a JSON API test library.

Tset-Noitamotua commented 5 years ago

@MrSteve2 have u found a solution meanwhile? How about an additional keyword POST XML?

ppazos commented 5 years ago

I think there is some conceptual problem with this issue and then a technical problem.

The conceptual problem is trying to implement SOAP over REST, which in many ways have different goals and different design principles. So basically, @MrSteve2 was treating this library as an HTTP lib not as a REST lib. IMO, for doing that you should get a plain HTTP lib or directly a SOAP lib.

On the other hand, REST means independence from the representation of the resource, JSON, XML, YAML, PDF, JPG, ... could be different representations for the same resource, and a REST lib should be able to handle them, or explicitly say a representation is not supported. When POSTing XML, there is a parse error and no info about an unsupported representation. @asyrjasalo maybe this lib should be called RESTinstanceJSON to avoid confusion if no other representation is supported.

humbienri commented 5 years ago

Agreed. At the very least, I would suggest to make it overabundantly clear in the documentation that this library is ONLY for sending and receiving JSON data. Somewhere obvious. I think this will alleviate and avoid a lot of redundant questions and petitions for support.