Search code examples
rubyxmlrest-client

translation from XML to rest-client for POST request


The is the XML request via POST I have to make in order to receive a response:

<BackgroundCheck userId="username" password="password">
  <BackgroundSearchPackage action="submit" type="demo product">
    <ReferenceId>some_id_value</ReferenceId>
    <PersonalData>
      <PersonName>
        <GivenName>John</GivenName>  
        <MiddleName>Q</MiddleName>
        <FamilyName>Test</FamilyName>
      </PersonName>
      <Aliases>
        <PersonName>
          <GivenName>Jack</GivenName>
          <MiddleName>Quigley</MiddleName>
          <FamilyName>Example</FamilyName>
        </PersonName>
      </Aliases>
      <DemographicDetail>
        <GovernmentId issuingAuthority="SSN">123456789</GovernmentId>
        <DateOfBirth>1973-12-25</DateOfBirth>
      </DemographicDetail>
      <PostalAddress>
        <PostalCode>83201</PostalCode>
        <Region>UT</Region>
        <Municipality>Salt Lake City</Municipality>
        <DeliveryAddress>
          <AddressLine>1234</AddressLine>
          <StreetName>Main Street</StreetName>
        </DeliveryAddress>
      </PostalAddress>
      <EmailAddress>john@test.com</EmailAddress>
      <Telephone>801-789-4229</Telephone>
    </PersonalData>
  </BackgroundCheck>
</BackgroundSearchPackage>

Using the examples on the rest-client github page I came up with the following translation using rest-client:

response = RestClient.post( 'url',
  {
    :BackgroundCheck => {
      :userID => 'username',
      :password => 'password',
    }, 
    :BackgroundSearchPackage => {
      :action => 'submit',
      :type => 'demo'
    }, 
    :ReferenceID => 'some_id_value', 
    :PersonalData => {
      :PersonalName => {
        :GivenName => 'John',
        :MiddleName => 'Q',
        :FamilyName => 'Test'
      }, 
       :Aliases => {
        :GivenName => 'Jack',
        :MiddleName => 'Quigly',
        :FamilyName => 'Example'
      }
    }, 
    :DemographicDetail => {
      :GovernmentId => {
        :issuingAuthority => "SSN"
      },  ## where do I enter the SSN?
      :DateOfBirth => '1972-12-25'
    }, 
    :PostalAddress => {
      :PostalCode => '83201',
      :Region => 'UT',
      :Municipality => 'Salt Lake City',
      :DeliveryAddress => {
        :AddressLine => '1234',
        :StreetName => 'Main Street'
      }
    }, 
    :EmailAddress => 'john@test.com', 
    :Telephone => '801-789-4229'
  })

Its my first time with XML and the rest-client gem.

My question is did I translate the XML correctly in the POST request?

More specifically how do I handle the GovernmentID and referencing the SSN entry?


Solution

  • First of all, the XML you've provided isn't valid! Your root element starts with BackgroundCheck and ends with BackgroundSearchPackage:

    <BackgroundCheck userId="username" password="password">
      <BackgroundSearchPackage action="submit" type="demo product">
      </BackgroundCheck>
    </BackgroundSearchPackage>
    

    In addition, your translation / transformation from XML to Ruby hash is incorrect. If BackgroundCheck is your root element and BackgroundSearchPackage is a child of it, your Ruby hash should look like this (rest-client accepts the string and the symbol notation):

    my_xml_hash = {
      "BackgroundCheck" => {
        "userId"=>"username",
        "password"=>"password",
        "BackgroundSearchPackage" => {
          "action"=>"submit",
          "type"=>"demo product",
          ...
          "PersonalData" => { ... },
          ...
        }
      }
    }
    

    You can access values in a Ruby hash like this:

    # string syntax
    my_xml_hash['BackgroundCheck']['BackgroundSearchPackage']['PersonalData']['DemographicDetail']['GovernmentId']
     => "123456789"
    
    # symbol syntax
    other_xml_hash[:BackgroundCheck][:BackgroundSearchPackage][:PersonalData][:DemographicDetail]['GovernmentId']
     => "123456789"
    



    If I understood you correctly, you want to send XML via a POST request. But if you use the hash syntax, you will not achieve the result, what you probably want, because rest-client will post your data as parameters and not as XML data!

    If you need to adjust only GovernmentID and issuingAuthority, I would do it as follows.

    require 'rest_client'
    
    # the customized 'GovernmentID'
    government_id = '123'
    
    # the customized 'issuingAuthority'
    issuing_authority = 'FOO'
    
    xml_template =<<END_OF_XML
      <BackgroundCheck userId="username" password="password">
        <BackgroundSearchPackage action="submit" type="demo product">
          <ReferenceId>some_id_value</ReferenceId>
          <PersonalData>
            <PersonName>
              <GivenName>John</GivenName>  
              <MiddleName>Q</MiddleName>
              <FamilyName>Test</FamilyName>
            </PersonName>
            <Aliases>
              <PersonName>
                <GivenName>Jack</GivenName>
                <MiddleName>Quigley</MiddleName>
                <FamilyName>Example</FamilyName>
              </PersonName>
            </Aliases>
            <DemographicDetail>
              <GovernmentId issuingAuthority="#{issuing_authority}">#{government_id}</GovernmentId>
              <DateOfBirth>1973-12-25</DateOfBirth>
            </DemographicDetail>
            <PostalAddress>
              <PostalCode>83201</PostalCode>
              <Region>UT</Region>
              <Municipality>Salt Lake City</Municipality>
              <DeliveryAddress>
                <AddressLine>1234</AddressLine>
                <StreetName>Main Street</StreetName>
              </DeliveryAddress>
            </PostalAddress>
            <EmailAddress>john@test.com</EmailAddress>
            <Telephone>801-789-4229</Telephone>
          </PersonalData>
        </BackgroundSearchPackage>
      </BackgroundCheck>
    END_OF_XML
    
    # Go to http://requestb.in/ , click on "Create a RequestBin", copy the "Bin URL" and use it for your tests ;-)
    response = RestClient.post('http://your.target.tld/your/webservice', xml_template, { content_type: :xml })
    
    puts "Response: #{response.inspect}"
    



    REXML example:

    require 'rest_client'
    require 'rexml/document'
    
    xml_string =<<END_OF_XML
      <BackgroundCheck userId="username" password="password">
        <BackgroundSearchPackage action="submit" type="demo product">
          <ReferenceId>some_id_value</ReferenceId>
          <PersonalData>
            <PersonName>
              <GivenName>John</GivenName>  
              <MiddleName>Q</MiddleName>
              <FamilyName>Test</FamilyName>
            </PersonName>
            <Aliases>
              <PersonName>
                <GivenName>Jack</GivenName>
                <MiddleName>Quigley</MiddleName>
                <FamilyName>Example</FamilyName>
              </PersonName>
            </Aliases>
            <DemographicDetail>
              <GovernmentId issuingAuthority="SSN">123456789</GovernmentId>
              <DateOfBirth>1973-12-25</DateOfBirth>
            </DemographicDetail>
            <PostalAddress>
              <PostalCode>83201</PostalCode>
              <Region>UT</Region>
              <Municipality>Salt Lake City</Municipality>
              <DeliveryAddress>
                <AddressLine>1234</AddressLine>
                <StreetName>Main Street</StreetName>
              </DeliveryAddress>
            </PostalAddress>
            <EmailAddress>john@test.com</EmailAddress>
            <Telephone>801-789-4229</Telephone>
          </PersonalData>
        </BackgroundSearchPackage>
      </BackgroundCheck>
    END_OF_XML
    
    # Build XML document from string
    doc = REXML::Document.new(xml_string)
    government_element = REXML::XPath.first(doc, "//GovernmentId")
    
    # Read values:
    puts government_element.text
    puts government_element.attributes['issuingAuthority']
    # OR directly via XPath
    puts REXML::XPath.first(doc, "//GovernmentId").text
    puts REXML::XPath.first(doc, "//GovernmentId/@issuingAuthority").value
    
    # Write values: 
    government_element.text = 'my new text value'
    government_element.attributes['issuingAuthority'] = 'my new attribute value'
    
    # Go to http://requestb.in/ , click on "Create a RequestBin", copy the "Bin URL" and use it for your tests ;-)
    response = RestClient.post('http://your.target.tld/your/webservice', doc.to_s, { content_type: :xml })
    
    puts "Response: #{response.inspect}"
    



    If you need to write complex XML trees, I recommend you to take a look at the following gems:

    Or use a templating engine like ERB, to simplify it.