XML Fetch API
fetch retrieves a response; XML parsing is a separate step. Check status and media type before interpreting a body as an exchange document.
How it works
These HTTP labs use the supplied Node 22 loopback server with fixed fictional data and no persistence. Save index.html and lab-server.mjs in one empty folder, run node lab-server.mjs and open http://127.0.0.1:8128. A successful network connection can still return an HTTP error or the wrong representation. Browser same-origin rules apply, so opening index.html as a file URL does not reproduce this server contract.
Run the code
Save this complete HTML source as index.html and open it in a normal browser. Select Run example to execute it. This lesson needs HTTP: save the loopback lab server beside index.html, run node lab-server.mjs with Node 22, and open http://127.0.0.1:8128. The fixed fixture never saves requests. Stop it with Ctrl+C. Browser DOM/XPath examples do not run in the XML syntax playground.
Download the complete http-fetch.html source. Keep each lab in its own folder. Sources are served as text, not as public executable server scripts. Review the starting setup.
Example
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Seed exchange XML lab</title><style>body{font:18px/1.6 system-ui;margin:24px;color:#0f3464}pre{white-space:pre-wrap;overflow-wrap:anywhere}button{font:inherit}main{max-width:55rem;margin:auto}</style></head>
<body><main><h1>Seed exchange XML lab</h1><button id="run" type="button">Run example</button><pre id="result" aria-live="polite"></pre></main>
<script>
document.querySelector('#run').addEventListener('click', async () => {
const show = value => document.querySelector('#result').textContent = String(value);
const parse = text => {
if (/<!\s*(DOCTYPE|ENTITY)/i.test(text)) throw new Error('Declarations disabled');
const doc = new DOMParser().parseFromString(text, 'application/xml');
if (doc.querySelector('parsererror')) throw new Error('Malformed XML');
return doc;
};
const doc = parse("<exchange region=\"west\">\n <packet id=\"p1\" available=\"true\"><name>Marigold</name><quantity>12</quantity><category>flower</category></packet>\n <packet id=\"p2\" available=\"false\"><name>Fenugreek</name><quantity>0</quantity><category>herb</category></packet>\n <packet id=\"p3\" available=\"true\"><name>Basil</name><quantity>7</quantity><category>herb</category></packet>\n</exchange>");
try {
const response = await fetch('/exchange.xml');
if (!response.ok) throw new Error('HTTP ' + response.status);
if (!response.headers.get('content-type')?.includes('application/xml')) throw new Error('Wrong media type');
const received = parse(await response.text());
show(received.documentElement.nodeName + ': ' + received.querySelectorAll('packet').length);
} catch (error) { show('Error: ' + error.message); }
});
</script></body></html>
Expected result
exchange: 3
The fixed endpoint returns XML with the correct header. Parsing then checks syntax and the document supplies three packets. A production caller should also enforce the expected vocabulary, input limits and application contract.
Check the exact contract in the XML specification, XPath 1.0, the XSD 1.0 primer, lxml validation documentation and Saxon’s processor documentation.