Skip to content
CMO & CTO
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

  • Digital Experience
    • Experience Strategy
    • Experience-Driven Commerce
    • Multi-Channel Experience
    • Personalization & Targeting
    • SEO & Performance
    • User Journey & Behavior
  • Marketing Technologies
    • Analytics & Measurement
    • Content Management Systems
    • Customer Data Platforms
    • Digital Asset Management
    • Marketing Automation
    • MarTech Stack & Strategy
    • Technology Buying & ROI
  • Software Engineering
    • Software Engineering
    • Software Architecture
    • General Software
    • Development Practices
    • Productivity & Workflow
    • Code
    • Engineering Management
    • Business of Software
    • Code
    • Digital Transformation
    • Systems Thinking
    • Technical Implementation
  • About
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

SOAP Endpoints that Don’t Hurt

Posted on December 27, 2007 By Luis Fernandez
\n

\n

\n

�Make it easy for people to do the right thing, and the right thing tends to happen.�

\n

\n

\n\n

\n

A coffee fueled wake up call

\n

I walked into the office with a lukewarm latte and a pager that would not stop blinking. A partner�s SOAP endpoint had slowed to a crawl. Sales said the web service was down. Ops said it was fine. The logs said everything and nothing at the same time. If you have shipped a WSDL, you know this morning.

\n

We had a mix of clients on the other side. .NET ASMX, a newer WCF pilot, Java JAX WS and a stubborn PHP SoapClient that was working until it was not. Everyone used the same WSDL but not the same defaults. The moment traffic moved from test to real data, tiny gaps turned into loud problems. That is when I learned the rule I keep taped to my screen: SOAP endpoints should not hurt.

\n

\n\n

\n

The day clients yelled at XML

\n

We were pushing a feature to let partners upload product images with MTOM. On paper, it looked clean. In practice, one client sent base64 inlined, another used MTOM, and a third sent attachments with an old library. Same contract, three behaviors. Tuning the server was easy. Tuning the expectations was the hard part. We kept telling people �just read the WSDL� like it was a map. It was closer to a menu in a language no one ordered in.

\n

That night I rewrote the service notes with a promise: make choices that work across stacks, set defaults that save people from sharp edges, and document what matters in the first screen a dev sees. This post is the distilled version of that effort. If you are working with SOAP, WSDL, HTTP, and the alphabet soup around them, here are three parts that keep endpoints from hurting.

\n

\n\n

\n

Design a WSDL that humans and tools can trust

\n

Tooling in Visual Studio, Eclipse, NetBeans, and PHP can read most WSDL documents, but small changes in style make a big difference. A tidy contract lowers support cost.

\n\n

    \n

  • Use document literal wrapped. Most stacks do best when operations have a single top level element. It generates cleaner code and predictable XML.
  • \n

  • Keep namespaces stable. Version with a URL that does not change on every build. For new versions, publish a new namespace. Example: urn example com api v1 then v2. Do not rename across releases.
  • \n

  • Be explicit with types. Avoid any type. Use xsd string, xsd int, xsd dateTime. If a value is optional, mark it nillable true and minOccurs zero.
  • \n

  • Describe fault contracts. A SOAP Fault with a clear code and a schema for details saves days.
  • \n

  • Publish examples. A well formed request and response next to the WSDL link does more than a paragraph of text.
  • \n

\n\n

Sample WSDL fragment that keeps things readable:

\n

<definitions \n  xmlns="http://schemas.xmlsoap.org/wsdl/"\n  xmlns:tns="urn:example:orders:v1"\n  xmlns:xsd="http://www.w3.org/2001/XMLSchema"\n  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"\n  targetNamespace="urn:example:orders:v1">\n\n  <types>\n    <xsd:schema targetNamespace="urn:example:orders:v1">\n      <xsd:element name="CreateOrderRequest">\n        <xsd:complexType>\n          <xsd:sequence>\n            <xsd:element name="customerId" type="xsd:string"/>\n            <xsd:element name="items" minOccurs="1" maxOccurs="unbounded">\n              <xsd:complexType>\n                <xsd:sequence>\n                  <xsd:element name="sku" type="xsd:string"/>\n                  <xsd:element name="qty" type="xsd:int"/>\n                </xsd:sequence>\n              </xsd:complexType>\n            </xsd:element>\n          </xsd:sequence>\n        </xsd:complexType>\n      </xsd:element>\n\n      <xsd:element name="CreateOrderResponse">\n        <xsd:complexType>\n          <xsd:sequence>\n            <xsd:element name="orderId" type="xsd:string"/>\n          </xsd:sequence>\n        </xsd:complexType>\n      </xsd:element>\n    </xsd:schema>\n  </types>\n\n  <message name="CreateOrderInput">\n    <part name="parameters" element="tns:CreateOrderRequest"/>\n  </message>\n  <message name="CreateOrderOutput">\n    <part name="parameters" element="tns:CreateOrderResponse"/>\n  </message>\n\n  <portType name="OrderServicePortType">\n    <operation name="CreateOrder">\n      <input message="tns:CreateOrderInput"/>\n      <output message="tns:CreateOrderOutput"/>\n    </operation>\n  </portType>\n\n  <binding name="OrderServiceBinding" type="tns:OrderServicePortType">\n    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>\n    <operation name="CreateOrder">\n      <soap:operation soapAction="urn:example:orders:v1:CreateOrder"/>\n      <input><soap:body use="literal"/></input>\n      <output><soap:body use="literal"/></output>\n    </operation>\n  </binding>\n</definitions>

\n\n

Quick client checks across stacks help catch surprises early. Here are tiny examples that hit the same operation.

\n\n

// C Sharp with WCF client proxy\nvar client = new OrderServiceClient();\nclient.InnerChannel.OperationTimeout = TimeSpan.FromSeconds(30);\nvar resp = client.CreateOrder(new CreateOrderRequest {\n  customerId = "123",\n  items = new[] { new OrderItem { sku = "ABC", qty = 2 } }\n});\nConsole.WriteLine(resp.orderId);

\n\n

// Java with JAX WS\nOrderService service = new OrderService();\nOrderServicePortType port = service.getOrderServicePort();\n((javax.xml.ws.BindingProvider) port).getRequestContext().put(\n  "com.sun.xml.ws.request.timeout", 30000\n);\nCreateOrderRequest req = new CreateOrderRequest();\nreq.setCustomerId("123");\n// add items...\nCreateOrderResponse res = port.createOrder(req);\nSystem.out.println(res.getOrderId());

\n\n

// PHP SOAP\n$client = new SoapClient("https://example.com/wsdl/orders.v1.wsdl", [\n  "trace" => 1,\n  "exceptions" => true,\n  "connection_timeout" => 30\n]);\n$res = $client->CreateOrder([\n  "customerId" => "123",\n  "items" => [["sku" => "ABC", "qty" => 2]]\n]);\necho $res->orderId;

\n\n

Notice the shared theme. Explicit timeouts, a clean soapAction, and simple structures. That keeps code gen predictable.

\n

\n\n

\n

Make SOAP over HTTP behave well

\n

SOAP is often blamed for slowness, but the slowness comes from choices around HTTP. If your endpoint is chatty, or sends heavy XML, or keeps sockets around for too long, you will feel it at peak traffic.

\n\n

    \n

  • Use HTTP 1.1 keep alive wisely. Reuse connections on the client. On the server, set sane idle timeouts so stuck clients do not hog sockets.
  • \n

  • Compress when messages are larger than a few kilobytes. Gzip plays well with XML. Test real payloads. Many stacks handle gzip without code changes.
  • \n

  • Stream big uploads. For images and docs, prefer MTOM. Do not base64 a ten meg image into a single string field unless you enjoy paging.
  • \n

  • Set SOAPAction and content type correctly. Missing or wrong values break older clients and some proxies.
  • \n

  • Limit entity size. Defend your server with a max request size and a read timeout. It protects against both bugs and bad actors.
  • \n

\n\n

Here is a tiny C Sharp server side sample that sets good defaults in WCF:

\n

<configuration>\n  <system.serviceModel>\n    <bindings>\n      <basicHttpBinding>\n        <binding name="OrderBinding" \n                 maxReceivedMessageSize="1048576"\n                 transferMode="Buffered"\n                 messageEncoding="Mtom">\n          <readerQuotas maxDepth="64"\n                        maxStringContentLength="8192"\n                        maxArrayLength="16384"\n                        maxBytesPerRead="4096"\n                        maxNameTableCharCount="16384" />\n          <security mode="Transport">\n            <transport clientCredentialType="None"/>\n          </security>\n        </binding>\n      </basicHttpBinding>\n    </bindings>\n    <services>\n      <service name="OrderService">\n        <endpoint address="" \n                  binding="basicHttpBinding" \n                  bindingConfiguration="OrderBinding"\n                  contract="IOrderService" />\n      </service>\n    </services>\n  </system.serviceModel>\n</configuration>

\n\n

On the Java side with Axis2 or JAX WS, you can turn on gzip and timeouts at the client level:

\n

// JAX WS gzip hint for Metro\nMap<String, Object> ctx = ((BindingProvider) port).getRequestContext();\nctx.put(com.sun.xml.ws.developer.JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);\nctx.put("com.sun.xml.ws.transport.http.client.streaming.chunk.size", 8192);\nctx.put("com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump", true);\nctx.put("com.sun.xml.ws.transport.http.client.HttpTransportPipe.keepalive", true);\n// timeouts\nctx.put("com.sun.xml.ws.request.timeout", 30000);\nctx.put("com.sun.xml.ws.connect.timeout", 10000);

\n\n

For PHP, keep it simple and set timeouts and compression:

\n

$opts = [\n  "trace" => 1,\n  "exceptions" => true,\n  "compression" => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,\n  "connection_timeout" => 15\n];\n$client = new SoapClient("https://example.com/wsdl/orders.v1.wsdl", $opts);

\n\n

Last tip in this area. Put a health ping and a version call in your service. A tiny operation like ping returns ok and version returns a string helps ops and helps partners validate reachability without sending real data.

\n

\n\n

\n

Security that does not break builds

\n

Every service needs safety. The trick is to choose the simplest model that fits the data. Many partners are behind managed networks and an SSL endpoint with basic auth is plenty. When you need message level features, WS Security brings signatures and tokens, but you must test across stacks.

\n\n

    \n

  • Start with SSL. It gives you transport privacy with little client code. Rotate certs on a calendar and warn partners weeks in advance.
  • \n

  • Use basic auth or a custom header for simple identity. It is boring and works across .NET, Java, PHP, Ruby SOAP4R, and Perl SOAP Lite.
  • \n

  • Move to WS Security UsernameToken for signed or timestamped calls. Keep clocks synced with NTP and set a small time window to prevent replay.
  • \n

  • Sign only what you must. Full message signature on large bodies hurts throughput. If you only need to prove who sent it, sign headers.
  • \n

  • Document cipher suites and TLS versions. Old clients surprise you at the worst time. Give them a known good set.
  • \n

\n\n

Example of a simple WS Security UsernameToken header embedded in a request:

\n

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"\n                  xmlns:urn="urn:example:orders:v1"\n                  xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">\n  <soapenv:Header>\n    <wsse:Security>\n      <wsse:UsernameToken>\n        <wsse:Username>partnerA</wsse:Username>\n        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">\n          secret\n        </wsse:Password>\n        <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2007-12-27T01:42:56Z</wsu:Created>\n      </wsse:UsernameToken>\n    </wsse:Security>\n  </soapenv:Header>\n  <soapenv:Body>\n    <urn:CreateOrderRequest>...</urn:CreateOrderRequest>\n  </soapenv:Body>\n</soapenv:Envelope>

\n\n

In WCF, binding choices keep security practical:

\n

<basicHttpBinding>\n  <binding name="SecureBasic" messageEncoding="Text">\n    <security mode="TransportWithMessageCredential">\n      <message clientCredentialType="UserName" />\n    </security>\n  </binding>\n</basicHttpBinding>

\n\n

In Java Metro JAX WS, a policy with username token can be referenced in the WSDL and handled with a callback on the server. Keep the samples ready for partners so they can copy and go.

\n

\n\n

\n

Reflective close

\n

People love to argue SOAP vs REST right now. REST is getting a lot of air thanks to lighter payloads and easy browser tools. Still, many of us are shipping SOAP for contracts, tools, and enterprise checklists. The way forward is not to fight the choice. The way forward is to make the choice kind.

\n

When I look back at the pager morning, it was not XML that bit us. It was a few defaults we left vague. Clear WSDLs, predictable HTTP behavior, and simple security cut support mail in half and kept partners moving. Add a small sample for .NET, for Java, and for PHP, and you just made three teams productive before lunch.

\n

Tools like SoapUI, Fiddler, and Wireshark are on my dock all day. Before you post the WSDL link, hit your own endpoint with those tools. Send a large payload. Kill the connection in the middle. Watch what the service does. Make the easy path the safe path.

\n

If you do that, your SOAP endpoint will not hurt. It will be boring in the best way. People will wire it up, forget it, and go build features that matter.

\n

\n

Software Architecture Software Engineering

Post navigation

Previous post
Next post
  • Digital Experience (94)
    • Experience Strategy (19)
    • Experience-Driven Commerce (5)
    • Multi-Channel Experience (9)
    • Personalization & Targeting (21)
    • SEO & Performance (10)
  • Marketing Technologies (92)
    • Analytics & Measurement (14)
    • Content Management Systems (45)
    • Customer Data Platforms (4)
    • Digital Asset Management (8)
    • Marketing Automation (6)
    • MarTech Stack & Strategy (10)
    • Technology Buying & ROI (3)
  • Software Engineering (310)
    • Business of Software (20)
    • Code (30)
    • Development Practices (52)
    • Digital Transformation (21)
    • Engineering Management (25)
    • General Software (82)
    • Productivity & Workflow (30)
    • Software Architecture (85)
    • Technical Implementation (23)
  • 2025 (12)
  • 2024 (8)
  • 2023 (18)
  • 2022 (13)
  • 2021 (3)
  • 2020 (8)
  • 2019 (8)
  • 2018 (23)
  • 2017 (17)
  • 2016 (40)
  • 2015 (37)
  • 2014 (25)
  • 2013 (28)
  • 2012 (24)
  • 2011 (30)
  • 2010 (42)
  • 2009 (25)
  • 2008 (13)
  • 2007 (33)
  • 2006 (26)

Ab Testing Adobe Adobe Analytics Adobe Target AEM agile-methodologies Analytics architecture-patterns CDP CMS coding-practices content-marketing Content Supply Chain Conversion Optimization Core Web Vitals customer-education Customer Data Platform Customer Experience Customer Journey DAM Data Layer Data Unification documentation DXP Individualization java Martech metrics mobile-development Mobile First Multichannel Omnichannel Personalization product-strategy project-management Responsive Design Search Engine Optimization Segmentation seo spring Targeting Tracking user-experience User Journey web-development

©2025 CMO & CTO | WordPress Theme by SuperbThemes