Jake Levi
Jake Levi

Reputation: 399

Struggling to interact with an API

I've been tasked with writing a program which interacts with the API for ClearBooks. They have some documentation but I'm still really struggling to get started. From what I can gather from the documentation, in order to receive the seemingly mythical "response 200", I need to:

  1. Post an 'XML request' to "https://secure.clearbooks.co.uk/api/soap/"
  2. Set the 'request http header' to "Content-Type: text/xml"
  3. Include a 'SOAP header' with my API key (which I have locally)

My current code is as follows:

import requests

url = "https://secure.clearbooks.co.uk/api/soap/"
headers = {"Content-Type": "text/xml", "apiKey": "(api key goes here)"}

response = requests.get(url=url, headers=headers)

print(response)
print(response.text)

>>> <Response [500]>
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>Sender</faultcode><faultstring>Invalid XML</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>

I'm aware that my code probably looks really stupid, however this is the first time I've tried to write a program that interacts with the internet, and despite having spent a few days trying to hack it, it's something I'm finding really difficult - I've managed to scrape text from generic webpages but haven't managed to interact with any APIs without Codecademy or similar. Please could someone update my code (or more likely go from scratch) so that it works? I realise it's not something you can test without your own Clearbooks API key, but any help would be very greatly appreciated.

Upvotes: 1

Views: 1000

Answers (2)

Anentropic
Anentropic

Reputation: 33823

Your code is not stupid at all.

But currently you are making an HTTP 'GET' request. This is the same as typing a url into your web browser and hitting enter.

Your first instruction though is to "post an XML request" to the SOAP server url. When you make a 'POST' request it's like when you submit a form on a web page. In other words you don't just request a url, you send some data to that url as well.

In this case you need to prepare a valid SOAP message, which is an XML document, and POST that to the SOAP server url.

See here: http://docs.python-requests.org/en/latest/user/quickstart/#more-complicated-post-requests

In this case we are not posting form-encoded data, we want to send the XML as a string (see second example at url above)

It's entirely possible to do this manually, by typing in the correct message as a string. But it's probably easier to at least use an XML lib such as lxml or a dedicated SOAP library such as suds to make this easier.

One thing I would point out is that a "SOAP Header" is part of the XML message and not the same as an HTTP header. http://www.w3schools.com/webservices/ws_soap_header.asp

You have correctly sent the Content-Type: text/xml HTTP header though, well done :)

Upvotes: 2

Jake Levi
Jake Levi

Reputation: 399

import requests

url = "https://secure.clearbooks.co.uk/api/soap/"
header = {"Content-Type": "text/xml"}
myxml = """<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"
    xmlns:cb="https://secure.clearbooks.co.uk/api/soap/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:enc="http://www.w3.org/2003/05/soap-encoding">
    <env:Header>
        <cb:authenticate apiKey="API_key_goes_here" />
    </env:Header>
    <env:Body>
        <env:listProjects env:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
            offset="3"
        </env:listProjects>
    </env:Body>
</env:Envelope>
"""

response = requests.post(url, data=myxml, headers=header)

print(response)

>>> <Response [200]>

Upvotes: 2

Related Questions