SOAP namespace alias changing on SOAP Service

Not applicable

Hi,

I'm creating and SOAP Service and for some reason Apigee is changing the alias.

Here are two examples, one from Apigee (capture on Trace) and other from SoapUI.

Apigee

<s12:Envelope 
    xmlns:s12="http://www.w3.org/2003/05/soap-envelope">
    <s12:Header 
        xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsse:Security soap:mustUnderstand="true" 
            xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
            xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsse:UsernameToken>
                <wsse:Username>****</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">****</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
        <wsa:To>https://someurl</wsa:To>
        <wsa:Action>http://ESB.Mongeral/Documento/IDocumento/ListaDocumentos</wsa:Action>
    </s12:Header>
    <s12:Body>
        <ns1:ListaDocumentos xmlns:ns1="http://ESB.Mongeral/Documento" />
    </s12:Body>
</s12:Envelope>

SoapUI

<soap:Envelope 
    xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <soap:Header 
        xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsse:Security soap:mustUnderstand="true" 
            xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
            xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsse:UsernameToken>
                <wsse:Username>****</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">****</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
        <wsa:To>https://someurl</wsa:To>
        <wsa:Action>http://ESB.Mongeral/Documento/IDocumento/ListaDocumentos</wsa:Action>
    </soap:Header>
    <soap:Body>
        <doc:ListaDocumentos xmlns:doc="http://ESB.Mongeral/Documento" />
    </soap:Body>
</soap:Envelope>

You'll notice that Apigee is changing "soap" and "doc" alias to "ns12" and "ns1".

WIth this change our service can't understand the message, and so, fails.

Is there any way to make Apigee follow what is on the wsdl?

1 1 6,367
1 REPLY 1

Bonus comment

you didn't ask about this, but...

The original XML you posted, labeled "Apigee", is not "namespace-valid." That document uses soap:mustUnderstand as an attribute name. And the soap prefix is not declared in the document, therefore the attribute is not valid.

If Apigee is indeed generating this document, there's a bug somewhere. A correct document, replaces this :

<s12:Envelope xmlns:s12="http://www.w3.org/2003/05/soap-envelope">
    <s12:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsse:Security soap:mustUnderstand="true"

with this :

<s12:Envelope xmlns:s12="http://www.w3.org/2003/05/soap-envelope">
    <s12:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsse:Security s12:mustUnderstand="true"

(Only the last line changes)

Please do tell me if it is Apigee Edge directly that is generating this document, or if it is some policy you've authored that's generating the document.


Answer to your Actual Question

You asked

Is there any way to make Apigee follow what is on the wsdl?

And the answer is "YES, but you shouldn't have to do that. "

First let me explain why you shouldn't have to do that. In fact your question is not valid. WSDL never stipulates a namespace prefix. No WSDL ever says, "the prefix must be 'soap'".

The value of an XML prefixes is not semantically important in XML. The prefix value is irrelevant; what's important is the actual namespace. An application such as

  • a client (or generator and sender of an XML payload),
  • a server (or a receiver/parser of an XML payload)
  • or otherwise (like a XML-parsing tool)

...must not use the prefix value during parsing, but rather should use only the actual namespace. The prefix is just a placeholder. The XML Namespaces specification from W3C states it like this:

Note that the prefix functions only as a placeholder for a namespace name. Applications should use the namespace name, not the prefix, in constructing names whose scope extends beyond the containing document.

A good analogy might be a variable in a program. Suppose I have two JavaScript apps. One is like this:

var fifteen = 15; 
console.log(fifteen);

We know that the output of the program will show "15" on the console.

Now suppose the other app is like this:

var dino = 15;
console.log(dino);

Still, the output is "15" . The variable name used in the latter is different than the variable used in the former, but the variables hold the same value, and the output is the same.

XML Namespaces are like variable names. The names are not important; the value of the variable is what is important. For a background on XML Namespaces, check out this article.

To give you some specific examples in XML, the following are all equivalent. In XML-speak, they all represent the same "XML Infoset" .

Example 1 - default namespace for soap

<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope">
  <Body>
    <ListaDocumentos xmlns="http://ESB.Mongeral/Documento"/>
  </Body>
</Envelope>

Example 2 - the customary prefix of "soap" for the "soap envelope" namespace

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Body>
    <ListaDocumentos xmlns="http://ESB.Mongeral/Documento"/>
  </soap:Body>
</soap:Envelope>

Example 3 - a non-customary namespace prefix for soap, and another namespace prefix for the inner element.

<dino:Envelope xmlns:dino="http://www.w3.org/2003/05/soap-envelope">
  <dino:Body>
    <ns1:ListaDocumentos xmlns:ns1="http://ESB.Mongeral/Documento"/>
  </dino:Body>
</dino:Envelope>

An XML processing application must treat all of these as exactly equivalent. It is an error if an XML application insists on a specific prefix value, or even the presence of a prefix. If your system is requiring soap as the prefix, your system is wrong. It's broken.

OK, so that is an explanation of WHY you should not need to do what you asked to do.

But we live in reality, where sometimes applications are broken, and they might actually insist on a specific prefix. Apigee is a powerful tool, and it can help you build more robust systems, in accordance with the Robustness principle, aka "Postel's Law", which says:

  • Applications should be conservative in what they send, and liberal in what they accept

You can add an XSLT policy into Apigee Edge that transforms a message so that it always uses the word "soap" for the prefix for the soap1.2 namespace (http://www.w3.org/2003/05/soap-envelope) , and so that it always uses the word "doc" when referring to http://ESB.Mongeral/Documento . You would need something like this XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
                xmlns:wsa="http://www.w3.org/2005/08/addressing"
                xmlns:doc="http://ESB.Mongeral/Documento"
                version="2.0">
  <xsl:output method="xml"
              indent="yes"/>
  <xsl:template match="soap:*">
    <xsl:element name="soap:{local-name()}">
      <xsl:choose>
        <xsl:when test="local-name()='Header'">
          <xsl:namespace name="wsa">http://www.w3.org/2005/08/addressing</xsl:namespace>
        </xsl:when>
      </xsl:choose>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
  </xsl:template>
  <xsl:template match="doc:*">
    <xsl:element name="doc:{local-name()}">
      <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
  </xsl:template>
  <xsl:template match="@soap:*">
    <xsl:attribute name="soap:{local-name()}" namespace="http://www.w3.org/2003/05/soap-envelope">
      <xsl:value-of select="."/>
    </xsl:attribute>
  </xsl:template>
  <xsl:template match="@*|node()">
    <xsl:copy copy-namespaces="no">
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

When I try this with the corrected XML (replacing the soap:mustUnderstand with s12:mustUnderstand), I get this output:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                     soap:mustUnderstand="true">
            <wsse:UsernameToken>
                <wsse:Username>****</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">****</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
        <wsa:To>https://someurl</wsa:To>
        <wsa:Action>http://ESB.Mongeral/Documento/IDocumento/ListaDocumentos</wsa:Action>
    </soap:Header>
    <soap:Body>
        <doc:ListaDocumentos xmlns:doc="http://ESB.Mongeral/Documento"/>
    </soap:Body>
</soap:Envelope>