Skip to content

Adding AccessToken changes header structure #1465

Description

@Kirina

Adding the AccessToken to the header adds the AccessToken as a nested field in the sessionID field. I was very confused as posting raw xml files the the server did give the correct response but when i switched to zeep I suddenly got messages that my header was misformed.

When I show the header structure I get the correctly formed header:

Empty header structure: {
    'SessionID': None,
    'AccessToken': None,
    'CompanyCode': None,
    'CompanyId': None,
    '_attr_1': None
}

When I then add the AccessToken, it is added to the SessionID:

Created header: {
    'SessionID': {
        'AccessToken': 'dummy_access_token_placeholder'
    },
    'AccessToken': None,
    'CompanyCode': None,
    'CompanyId': None,
    '_attr_1': None
}

I also tried to add both the SessionID and AccessToken to see if that fixed it, but then they just both get added to the SessionID:

Created header: {
    'SessionID': {
        'SessionID': None,
        'AccessToken': 'dummy_access_token_placeholder'
    },
    'AccessToken': None,
    'CompanyCode': None,
    'CompanyId': None,
    '_attr_1': None
}

This is the code that I used to create this issue:

from zeep import Client
from zeep.plugins import HistoryPlugin

# zeep==4.3.1

def process_xml_with_zeep(wsdl_url: str, access_token: str):
    client = Client(wsdl_url, plugins=[HistoryPlugin()])

    header_element = client.get_element("ns0:Header")
    print(f"Header element signature: {header_element.signature}")
    print(f"Header element type: {header_element.type}")

    # Empty header gives the correct structure
    empty_header = header_element()
    print(f"Empty header structure: {empty_header}")

    # But the AccessToken somehow gets added to the sessionId as a nested list
    header_data = {"AccessToken": access_token}
    soap_header = header_element(header_data)
    print(f"Created header: {soap_header}")

cluster_url = "https://api.accounting.twinfield.com"
url = f"{cluster_url}/webservices/processxml.asmx?wsdl"
access_token = "dummy_access_token_placeholder"
process_xml_with_zeep(
    wsdl_url=url,
    access_token=access_token,
)

My current solution is to use a manual header construction and avoid zeep for this step and that does work:

def process_xml_with_zeep_manual(access_token: str):
    header = etree.Element(
        "{http://www.twinfield.com/}Header",
        nsmap={None: "http://www.twinfield.com/"},
    )

    # Add AccessToken as direct child
    access_token_elem = etree.SubElement(header, "AccessToken")
    access_token_elem.text = access_token
    print(f"Manual header XML: {etree.tostring(header, pretty_print=True).decode()}")

cluster_url = "https://api.accounting.twinfield.com"
url = f"{cluster_url}/webservices/processxml.asmx?wsdl"
access_token = "dummy_access_token_placeholder"
process_xml_with_zeep_manual(access_token=access_token)

This gives:

Manual header XML: <Header xmlns="http://www.twinfield.com/">
  <AccessToken>dummy_access_token_placeholder</AccessToken>
</Header>

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions