-
-
Save davidlumley/5633664 to your computer and use it in GitHub Desktop.
=begin | |
====== | |
example Savon client for connecting to AutoTask's SOAP API | |
- install savon via `gem install savon` | |
- ensure AUTOTASK_USERNAME and AUTOTASK_PASSWORD environment variables are set | |
===== | |
=end | |
require 'rubygems' | |
require 'savon' | |
AUTOTASK_WSDL = 'https://webservices2.autotask.net/atservices/1.5/atws.wsdl' | |
AUTOTASK_USERNAME = ENV['AUTOTASK_USERNAME'] | |
AUTOTASK_PASSWORD = ENV['AUTOTASK_PASSWORD'] | |
def autotask_client | |
@autotask_client ||= Savon::Client.new( | |
:wsdl => AUTOTASK_WSDL, | |
:basic_auth => [ | |
AUTOTASK_USERNAME, | |
AUTOTASK_PASSWORD, | |
], | |
:raise_errors => false, | |
:log_level => :debug, | |
:log => true, | |
) | |
end | |
### | |
# returns 200, expected response body | |
# | |
autotask_client.call(:get_zone_info, :message => { | |
'UserName' => AUTOTASK_USERNAME, | |
}) | |
## | |
# returns 200, expected response body | |
# | |
autotask_client.call(:get_entity_info, :message => { | |
'UserName' => AUTOTASK_USERNAME, | |
}) | |
## | |
# empty queryxml, should return 400 (or similar) with errors | |
# returns 200, error in response body | |
# | |
# <ReturnCode>-1</ReturnCode> | |
# <EntityResults /><EntityResultType /> | |
# <Errors> | |
# <ATWSError><Message>Root element is missing.</Message></ATWSError> | |
# <ATWSError><Message>Error reading in Query XML.</Message></ATWSError> | |
# </Errors> | |
# <EntityReturnInfoResults /> | |
autotask_client.call(:query, :message => { | |
'sXML' => { | |
:queryxml => {} | |
} | |
}) | |
## | |
# contains valid queryxml, should return 200 and entities | |
# doesn't work, returns 400 | |
# | |
# empty response body | |
# | |
autotask_client.call(:query, :message => { | |
'sXML' => { | |
:queryxml => { | |
:entity => 'Contact', | |
:query! => '<condition><field>id<expression op="greaterthan">0</expression></field></condition>', # use ! to prevent escaping of internal fields | |
} | |
} | |
}) |
# Testing the create method to create account notes. | |
<?xml version="1.0" encoding="utf-8"?> | |
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<soap:Body> | |
<create xmlns="http://autotask.net/ATWS/v1_5/"> | |
<Entities> | |
<Entity type="AccountNote"> | |
<AccountID>29683561</AccountID> | |
<AssignedResourceID>29684288</AssignedResourceID> | |
<ActionType>4</ActionType> | |
<StartDateTime>2013-07-08 05:48:55</StartDateTime> | |
<EndDateTime>2013-07-15 05:48:55</EndDateTime> | |
<Name>Note 1</Name> | |
<Note>This is the first note.</Note> | |
</Entity> | |
<Entity type="AccountNote"> | |
<AccountID>29683561</AccountID> | |
<AssignedResourceID>29684288</AssignedResourceID> | |
<ActionType>4</ActionType> | |
<StartDateTime>2013-07-08 05:48:55</StartDateTime> | |
<EndDateTime>2013-07-15 05:48:55</EndDateTime> | |
<Name>Note 2</Name> | |
<Note>This is the second note.</Note> | |
</Entity> | |
<Entity type="AccountNote"> | |
<AccountID>29683561</AccountID> | |
<AssignedResourceID>29684288</AssignedResourceID> | |
<ActionType>4</ActionType> | |
<StartDateTime>2013-07-08 05:48:55</StartDateTime> | |
<EndDateTime>2013-07-15 05:48:55</EndDateTime> | |
<Name>Note 3</Name> | |
<Note>This is the last note.</Note> | |
</Entity> | |
</Entities> | |
</create> | |
</soap:Body> | |
</soap:Envelope> | |
----- | |
<?xml version="1.0" encoding="utf-8"?> | |
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<soap:Body> | |
<soap:Fault> | |
<faultcode>soap:Client</faultcode> | |
<faultstring>System.Web.Services.Protocols.SoapException: Server was unable to read request. ---> System.InvalidOperationException: There is an error in XML document (4, 63). ---> System.InvalidOperationException: The specified type is abstract: name='Entity', namespace='http://autotask.net/ATWS/v1_5/', at <Entity xmlns='http://autotask.net/ATWS/v1_5/'>. | |
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read5_Entity(Boolean isNullable, Boolean checkType) | |
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read132_create() | |
at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer92.Deserialize(XmlSerializationReader reader) | |
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events) | |
--- End of inner exception stack trace --- | |
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events) | |
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle) | |
at System.Web.Services.Protocols.SoapServerProtocol.ReadParameters() | |
--- End of inner exception stack trace --- | |
at System.Web.Services.Protocols.SoapServerProtocol.ReadParameters() | |
at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()</faultstring> | |
<detail /> | |
</soap:Fault> | |
</soap:Body> | |
</soap:Envelope> |
# Testing the creation of entities using raw soap request | |
<?xml version="1.0" encoding="utf-16"?> | |
<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> | |
<create xmlns="http://autotask.net/ATWS/v1_5/"> | |
<Entities> | |
<Entity xsi:type="AccountNote"> | |
<AccountID>29683561</AccountID> | |
<ActionType>3</ActionType> | |
<AssignedResourceID>29684288</AssignedResourceID> | |
<EndDateTime>2013-07-15 05:48:55</EndDateTime> | |
<Name>Note 2</Name> | |
<Note>This is the second note.</Note> | |
<StartDateTime>2013-07-08 05:48:55</StartDateTime> | |
</Entity> | |
</Entities> | |
</create> | |
</soap:Body> | |
</soap:Envelope> | |
---------- | |
<?xml version="1.0" encoding="utf-8"?> | |
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<soap:Body> | |
<queryResponse xmlns="http://autotask.net/ATWS/v1_5/"> | |
<queryResult> | |
<ReturnCode>-1</ReturnCode> | |
<EntityResults /> | |
<EntityResultType /> | |
<Errors> | |
<ATWSError> | |
<Message>Object reference not set to an instance of an object.</Message> | |
</ATWSError> | |
<ATWSError> | |
<Message>Error reading in Query XML.</Message> | |
</ATWSError> | |
</Errors> | |
<EntityReturnInfoResults /> | |
</queryResult> | |
</queryResponse> | |
</soap:Body> | |
</soap:Envelope> |
# Example from https://webservices2.autotask.net/atservices/1.5/atws.asmx?op=query | |
# I assume the contents of the `sXML` attribute are the `queryxml` | |
<?xml version="1.0" encoding="utf-8"?> | |
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"> | |
<soap12:Header> | |
<AutotaskIntegrations xmlns="http://autotask.net/ATWS/v1_5/"> | |
<PartnerID>string</PartnerID> | |
</AutotaskIntegrations> | |
</soap12:Header> | |
<soap12:Body> | |
<query xmlns="http://autotask.net/ATWS/v1_5/"> | |
<sXML>string</sXML> | |
</query> | |
</soap12:Body> | |
</soap12:Envelope> |
# Correctly runs GetEntityInfo and returns a list of entities | |
<?xml version="1.0" encoding="UTF-8"?> | |
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://autotask.net/ATWS/v1_5/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> | |
<env:Body> | |
<tns:GetEntityInfo></tns:GetEntityInfo> | |
</env:Body> | |
</env:Envelope> |
# Correctly returns the appropriate zone to use | |
<?xml version="1.0" encoding="UTF-8"?> | |
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://autotask.net/ATWS/v1_5/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> | |
<env:Body> | |
<tns:getZoneInfo> | |
<tns:UserName>[email protected]</tns:UserName> | |
</tns:getZoneInfo> | |
</env:Body> | |
</env:Envelope> |
# Responds with HTTP 400, empty body | |
<?xml version="1.0" encoding="UTF-8"?> | |
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://autotask.net/ATWS/v1_5/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> | |
<env:Body> | |
<tns:query> | |
<tns:sXML> | |
<tns:queryxml> | |
<tns:entity>Contact</tns:entity> | |
<tns:query> | |
<field>id | |
<expression op="greaterthan">0</expression></field> | |
</tns:query> | |
</tns:queryxml> | |
</tns:sXML> | |
</tns:query> | |
</env:Body> | |
</env:Envelope> |
# Experimenting with the XML structure yields no gains. | |
# Without `sXML` | |
<?xml version="1.0" encoding="UTF-8"?> | |
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://autotask.net/ATWS/v1_5/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> | |
<env:Body> | |
<tns:query> | |
<queryxml> | |
<entity>Contact</entity> | |
<query> | |
<condition> | |
<field>id<expression op="greaterthan">0</expression></field> | |
</condition> | |
</query> | |
</queryxml> | |
</tns:query> | |
</env:Body> | |
</env:Envelope> | |
----- | |
<?xml version="1.0" encoding="utf-8"?> | |
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<soap:Body> | |
<queryResponse xmlns="http://autotask.net/ATWS/v1_5/"> | |
<queryResult> | |
<ReturnCode>-1</ReturnCode> | |
<EntityResults /> | |
<EntityResultType /> | |
<Errors> | |
<ATWSError> | |
<Message>Object reference not set to an instance of an object.</Message> | |
</ATWSError> | |
<ATWSError> | |
<Message>Error reading in Query XML.</Message> | |
</ATWSError> | |
</Errors> | |
<EntityReturnInfoResults /> | |
</queryResult> | |
</queryResponse> | |
</soap:Body> | |
</soap:Envelope> | |
----- | |
# Without `queryxml` | |
<?xml version="1.0" encoding="UTF-8"?> | |
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://autotask.net/ATWS/v1_5/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> | |
<env:Body> | |
<sXML> | |
<queryxml> | |
<entity>Contact</entity> | |
<query> | |
<condition> | |
<field>id<expression op="greaterthan">0</expression></field> | |
</condition> | |
</query> | |
</queryxml> | |
</sXML> | |
</env:Body> | |
</env:Envelope> | |
----- | |
<?xml version="1.0" encoding="utf-8"?> | |
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<soap:Body> | |
<queryResponse xmlns="http://autotask.net/ATWS/v1_5/"> | |
<queryResult> | |
<ReturnCode>-1</ReturnCode> | |
<EntityResults /> | |
<EntityResultType /> | |
<Errors> | |
<ATWSError> | |
<Message>Object reference not set to an instance of an object.</Message> | |
</ATWSError> | |
<ATWSError> | |
<Message>Error reading in Query XML.</Message> | |
</ATWSError> | |
</Errors> | |
<EntityReturnInfoResults /> | |
</queryResult> | |
</queryResponse> | |
</soap:Body> | |
</soap:Envelope> |
# Properly formed, and as per the documentation. | |
# Also fails. | |
<?xml version="1.0" encoding="UTF-8"?> | |
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://autotask.net/ATWS/v1_5/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> | |
<env:Body> | |
<tns:query> | |
<sXML> | |
<queryxml> | |
<entity>Contact</entity> | |
<query> | |
<condition> | |
<field>id<expression op="greaterthan">0</expression></field> | |
</condition> | |
</query> | |
</queryxml> | |
</sXML> | |
</tns:query> | |
</env:Body> | |
</env:Envelope> | |
----- | |
<?xml version="1.0" encoding="utf-8"?> | |
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<soap:Body> | |
<queryResponse xmlns="http://autotask.net/ATWS/v1_5/"> | |
<queryResult> | |
<ReturnCode>-1</ReturnCode> | |
<EntityResults /> | |
<EntityResultType /> | |
<Errors> | |
<ATWSError> | |
<Message>Object reference not set to an instance of an object.</Message> | |
</ATWSError> | |
<ATWSError> | |
<Message>Error reading in Query XML.</Message> | |
</ATWSError> | |
</Errors> | |
<EntityReturnInfoResults /> | |
</queryResult> | |
</queryResponse> | |
</soap:Body> | |
</soap:Envelope> |
# A properly formed request, with the `queryxml` as the body. | |
# This also fails as expected, the API document specified the `queryxml` should be contained within `query` and `sXML` | |
<?xml version="1.0" encoding="UTF-8"?> | |
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://autotask.net/ATWS/v1_5/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> | |
<env:Body> | |
<queryxml> | |
<entity>Contact</entity> | |
<query> | |
<condition> | |
<field>id<expression op="greaterthan">0</expression></field> | |
</condition> | |
</query> | |
</queryxml> | |
</env:Body> | |
</env:Envelope> | |
----- | |
<?xml version="1.0" encoding="utf-8"?> | |
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<soap:Body> | |
<queryResponse xmlns="http://autotask.net/ATWS/v1_5/"> | |
<queryResult> | |
<ReturnCode>-1</ReturnCode> | |
<EntityResults /> | |
<EntityResultType /> | |
<Errors> | |
<ATWSError> | |
<Message>Object reference not set to an instance of an object.</Message> | |
</ATWSError> | |
<ATWSError> | |
<Message>Error reading in Query XML.</Message> | |
</ATWSError> | |
</Errors> | |
<EntityReturnInfoResults /> | |
</queryResult> | |
</queryResponse> | |
</soap:Body> | |
</soap:Envelope> |
# As expected, using `queryxml` as the request fails with SOAP error. | |
<?xml version="1.0"?> | |
<queryxml> | |
<entity>Contact</entity> | |
<query> | |
<condition> | |
<field>id<expression op="greaterthan">0</expression></field> | |
</condition> | |
</query> | |
</queryxml> | |
----- | |
<?xml version="1.0" encoding="utf-8"?> | |
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<soap:Header> | |
<soap12:Upgrade xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"> | |
<soap12:SupportedEnvelope qname="soap:Envelope" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" /> | |
<soap12:SupportedEnvelope qname="soap12:Envelope" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope" /> | |
</soap12:Upgrade> | |
</soap:Header> | |
<soap:Body> | |
<soap:Fault> | |
<faultcode>soap:VersionMismatch</faultcode> | |
<faultstring> | |
System.Web.Services.Protocols.SoapException: Possible SOAP version mismatch: Envelope namespace was unexpected. Expecting http://schemas.xmlsoap.org/soap/envelope/. | |
at System.Web.Services.Protocols.SoapServerProtocol.CheckHelperVersion() | |
at System.Web.Services.Protocols.SoapServerProtocol.ReadParameters() | |
at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest() | |
</faultstring> | |
<detail /> | |
</soap:Fault> | |
</soap:Body> | |
</soap:Envelope> |
# Testing with use of CDATA ( http://stackoverflow.com/questions/5227333/xml-soap-post-error-what-am-i-doing-wrong/7628604#7628604 ) | |
# All these SOAP requests are well formed according to the API documentation, not sure why it can't find the entity / queryxml. | |
<?xml version="1.0" encoding="UTF-8"?> | |
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://autotask.net/ATWS/v1_5/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> | |
<env:Body> | |
<tns:query> | |
<sXML> | |
<![CDATA[<queryxml> | |
<entity>Contact</entity> | |
<query> | |
<field>id<expression op="greaterthan">0</expression></field> | |
</query> | |
</queryxml>]]> | |
</sXML> | |
</tns:query> | |
</env:Body> | |
</env:Envelope> | |
----- | |
<?xml version="1.0" encoding="utf-8"?> | |
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<soap:Body> | |
<queryResponse xmlns="http://autotask.net/ATWS/v1_5/"> | |
<queryResult> | |
<ReturnCode>-1</ReturnCode> | |
<EntityResults /> | |
<EntityResultType /> | |
<Errors> | |
<ATWSError> | |
<Message>Object reference not set to an instance of an object.</Message> | |
</ATWSError> | |
<ATWSError> | |
<Message>Error reading in Query XML.</Message> | |
</ATWSError> | |
</Errors> | |
<EntityReturnInfoResults /> | |
</queryResult> | |
</queryResponse> | |
</soap:Body> | |
</soap:Envelope> |
Thanks @scoop; hadn't updated it but you are correct. I'll keep an eye on your wrapper too!
Just battled the same error as on your create_notes.xml. On the Entity type you need to prefix it with the "xsi" namespace. <Entity xsi:type="AccountNote">
Thank you! Thank you! Thank you!
Inserting <![CDATA[ ]] was the trick. I've been racking my brain about this one!
Very glad I bumped into this reference...doing some work with their API via Rails as well, and the documentation is considerably lacking. Glad you posted your findings.
I still can't get past this error :(
Excellent work, many thanks!!!
I spent an inordinate amount of time getting this to work so I thought I'd post my results.
First, I learned it made a difference which web service end point I used. For some reason I was getting "Unhandled Exception" HTTP 500 errors when accessing https://webservices3.autotask.net/ATServices/1.5/atws.asmx
but the same query and user/password works with https://webservices5.autotask.net/ATServices/1.5/atws.asmx
.
I used SOAPUI to run the below query. Note you need to specify your AutoTask username/password in the HTTP Basic Auth portion of SOAPUI (I had tried to use the SOAP Header to make it work).
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://autotask.net/ATWS/v1_5/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<tns:query>
<tns:sXML>
<![CDATA[
<queryxml>
<entity>Contact</entity>
<query>
<field>id
<expression op="equals">13500304</expression></field>
</query>
</queryxml>
]]>
</tns:sXML>
</tns:query>
</env:Body>
</env:Envelope>
Thank you all and @aaronbartell ! That query works for ticket IDs as well.
Using this CDATA
and xmlns
, how would you structure a create
request. To create a TicketNote
?
A combination of
CDATA
and an additionalxmlns
declaration on the SOAP action seems to do the trick.I stumbled upon your Gist while doing research for the Autotask Ruby API wrapper I started working on today.