简体   繁体   中英

Soap Request Format when using Savon in ruby

I am dealing with a soap api which offers the following as an example of how the request XML should look:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsg="http://tempuri.org/wsGenRateEstimate/">
   <soap:Header/>
   <soap:Body>
      <RateEstimateRequestVO>
         <Token>7e2c61c4-8b4c-4d8b-b47f-ed033c6f4307</Token>
         <CustomerNumber>1</CustomerNumber>
         <OriginCity>Dothan</OriginCity>
         <OriginState>AL</OriginState>
         <OriginZip>36303</OriginZip>
         <OriginCountryCode>USA</OriginCountryCode>
         <DestinationCity>Atlanta</DestinationCity>
         <DestinationState>GA</DestinationState>
         <DestinationZip>30303</DestinationZip>
         <DestinCountryCode>USA</DestinCountryCode>
         <WhoAmI>S</WhoAmI>
         <BillDate>050415</BillDate>
         <CODAmount></CODAmount>
         <CODPayType></CODPayType>
         <CODFeePaidBy></CODFeePaidBy>
         <FullCoverage>Y</FullCoverage>
         <FullCoverageAmount>32545</FullCoverageAmount>
         <PrePaidCollect></PrePaidCollect>
         <TotalPalletCount></TotalPalletCount>
         <!--Zero or more repetitions:-->
         <AccLine>
            <AccCode></AccCode>
         </AccLine>
         <!--Zero or more repetitions:-->
         <RateEstimateRequestLine>
            <Weight>122</Weight>
            <Class>70</Class>
            <HandlingUnits></HandlingUnits>
            <HandlingUnitType></HandlingUnitType>
            <Hazmat></Hazmat>
            <CubeU></CubeU>
            <Length></Length>
            <Height></Height>
            <Width></Width>
         </RateEstimateRequestLine>
      </RateEstimateRequestVO>
   </soap:Body>
</soap:Envelope>

Below is the code I am using to attempt this request in rails (covering up my access token for privacy's sake):

require 'savon'
client = Savon.client({ wsdl: "http://wsportal.aaacooper.com:8188/wsGenRateEstimate.wsdl" })
# this part is to check what the XML I am sending will look like
request = client.build_request(:ws_gen_rate_estimate, message: { Token: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", OriginCity: "Birmingham", OriginState: "AL", OriginZip: "35222", OriginCountryCode: "USA", DestinationCity: "New Orleans", DestinationState: "LA", DestinationZip: "70122", DestinCountryCode: "USA", CustomerNumber: "000971733", WhoAmI: "S", PrePaidCollect: "" })
# This will actually send the xml to the server api
response = client.call(:ws_gen_rate_estimate, message: { Token: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", OriginCity: "Birmingham", OriginState: "AL", OriginZip: "35222", OriginCountryCode: "USA", DestinationCity: "New Orleans", DestinationState: "LA", DestinationZip: "70122", DestinCountryCode: "USA", CustomerNumber: "000971733", WhoAmI: "S", PrePaidCollect: "" })
render json: {
  "this is a": "test",
  "client_request": request.body,
  "client_response": response.body,
}, status: :ok

The response to this request has an "error_message" saying my Token is invalid, however I know I have a valid token, and I know that it is pasted in full in the code there. Here is what the XML looks like being sent to the server:

<?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://tempuri.org/wsGenRateEstimate/\" xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\">
        <env:Body>
           <tns:RateEstimateRequestVO>
              <token>XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</token>
              <originCity>Birmingham</originCity>
              <originState>AL</originState>
              <originZip>35222</originZip>
              <originCountryCode>USA</originCountryCode>
              <destinationCity>New Orleans</destinationCity>
              <destinationState>LA</destinationState>
              <destinationZip>70122</destinationZip>
              <destinCountryCode>USA</destinCountryCode>
              <customerNumber>000971733</customerNumber>
              <whoAmI>S</whoAmI>
              <prePaidCollect></prePaidCollect>
            </tns:RateEstimateRequestVO>
        </env:Body>
     </env:Envelope>

The tag names and namespaces are different than the example asks for. Could this cause the API to not find the token? If so, does the savon gem provide options to change tag names or attributes?

The node that your Savon is producing is called token whereas the service is expecting to receive Token (with capital T ). As you can see, all the nodes have the same problem: they are sent with the initial letter in lowercase and they are expected to be received in uppercase.

Savon by default will convert keys to lowerCamelcase. You can change this behavior in the global convert_request_keys_to .

The options to this global are :camelcase , :lower_camelcase , :upcase and :none . In your problem, you should use :camelcase .

require 'savon'
client = Savon.client(
  wsdl: "http://wsportal.aaacooper.com:8188/wsGenRateEstimate.wsdl",
  convert_request_keys_to: :camelcase
)

This way, you can send your request as:

request = client.build_request(:ws_gen_rate_estimate, message: { token: "XXXXX", origin_city: "Birmingham" })

And the keys will be converted to its corresponding camelcase. Note that you can write them in snakecase and will be transformed correctly.

This might help as it worked for me following railscasts

Gyoku.convert_symbols_to :camelcase

For example:

def initialize(test)
  Gyoku.convert_symbols_to :camelcase
  client = Savon::Client.new("wsdl_link")
  response = client.request :web, :get_actions, body: { "test" => test }
  if response.success?
  // enter code
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM