XML Web Services

In the 2000s, systems talked in SOAP messages described by WSDL contracts, with the simpler XML-RPC before them. JSON APIs replaced them for new work, but banks, airlines, governments and enterprise suites still expose SOAP, so ingestion jobs need a client: zeep 4.3.3 (github.com/mvantellingen/python-zeep (https://github.com/mvantellingen/python-zeep 2,010 ), MIT; pip 21,050 install zeep==4.3.3). A small BookNest pricing service answers SOAP and plain HTTP on port 31081:

server.py: one pricing service, SOAP and plain HTTPPython
import json, threading
from http.server import BaseHTTPRequestHandler as Base, ThreadingHTTPServer
from lxml import etree
BOOKS = {b.findtext("identifier"): b for b in etree.parse("booknest-catalog.xml").iter("book")}
ENV = ('<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">'
       '<s:Body>%s</s:Body></s:Envelope>')
class Handler(Base):
    def send(self, status, ctype, body):
        self.send_response(status); self.send_header("Content-Type", ctype); self.end_headers()
        self.wfile.write(body.encode())
    def do_GET(self):                                   # REST: /books/<sku>
        if (b := BOOKS.get(self.path[7:])) is None:
            return self.send(404, "text/plain", "no such book")
        if "json" in self.headers.get("Accept", ""):    # content negotiation
            data = {"sku": b.findtext("identifier"), "price": b.findtext(".//price")}
            return self.send(200, "application/json", json.dumps(data))
        self.send(200, "application/xml", etree.tostring(b, encoding="unicode"))
    def do_POST(self):                                  # SOAP: GetPrice
        req = etree.fromstring(self.rfile.read(int(self.headers["Content-Length"])))
        sku = req.findtext(".//{urn:booknest:pricing}sku")
        if (b := BOOKS.get(sku)) is None:               # a fault travels as HTTP 500
            return self.send(500, "text/xml", ENV % "<s:Fault><faultcode>s:Client</faultcode>"
                             f"<faultstring>Unknown SKU {sku}</faultstring></s:Fault>")
        stock = str(b.findtext(".//availability") == "in-stock").lower()
        self.send(200, "text/xml", ENV % '<GetPriceResponse xmlns="urn:booknest:pricing">'
                  f'<price>{b.findtext(".//price")}</price><inStock>{stock}</inStock>'
                  "</GetPriceResponse>")
    def log_message(self, *args): pass
def start():                                            # serve from a background thread
    server = ThreadingHTTPServer(("127.0.0.1", 31081), Handler)
    threading.Thread(target=server.serve_forever, daemon=True).start()
    return server

Subsections


Web Services

A web service is a way for two machines to communicate over a network. Different software systems often need to exchange data with each other, and a web service provides a standard way of doing so over the internet.

This section covers the following technologies used to describe, exchange, and call web services: