-
-
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
CDATAand an additionalxmlnsdeclaration 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.