Can a canister return generated xml?

For my project, a host for rss feeds for podcasts, an xml file needs to be returned containing links to media determined from the data in the canister.

But I can’t figure out how to get a canister to return generated xml that a podcast player can parse.

A normal canister won’t work because it only returns data in Candid format, which podcast readers can’t parse.

An asset canister won’t work because, as far as I know, it must go through webpack or can only return static assets. I need to generate the xml on the fly based on the data in the canister and the values in the url. I tried using Mithril for simple routing/url parsing, but because it still goes through webpack I can’t serve just the generated xml. It’s always polluted by the single-page-application scaffolding that webpack forces upon me.

Is it possible to get just a generated xml feed out of the IC?

1 Like

Maybe I’m misunderstanding your question, but can’t you just create a query function in a canister that creates your XML document and returns it as a string? You could then call that function from your frontend JS to further process (parse) it.

Those were my thoughts exactly, but I ran into a couple problems with that solution.

Say I have the following query function:

public query func getXml(): async Text {
    return "<?xml version='1.0'?><rss xmlns:itunes=...";
};

Instead of getting back just the xml, I get back the candid string including the parenthesis and double-quote:

dfx canister call myCanister getXml
("<?xml version='1.0'?><rss xmlns:itunes=...")

That’s not going to be parsed successfully by all podcast players. The xml needs to start with <?xml not ("<?xml.

Even if it did, I don’t know how to get the results of that function just by fetching a url in a browser or curl command. What’s the syntax for calling a canister function by specifying the function name and parameters in the url, similar to how you can use dfx canister call in the terminal? Is that even possible?

I was hoping I could discover the url format by loading up http://127.0.0.1:8000/candid?canisterId= for my canister and pressing the Query button under getXml(), but that sends off a POST request to http://127.0.0.1:8000/api/v1/read with an unintelligible payload:

ÙÙ÷£gcontent¦cargFDIDLkcanister_idRningress_expiryeO!¨¬í€kmethod_namefgetXmllrequest_typeequeryfsenderXí·ïƒ@¥î›Êç0„¶ÆäêKÉð‚msender_pubkeyX óæ#
íü8®Šª@"çǟ†­å´ÞÀÚb¥M¤[email protected]¹¹ä´›µ‰eÎó™yoRŒä\9±žÆÇ'¨y9½D‚–>‘ùëȁpŠ|™ggàóK\\]´0í…Ó<N€(Á

Surely that’s not how I’m supposed to interact with my canister via curl. Is it possible to do so?

I haven’t been able to get the latter idea to work either, using frontend JS to parse and return just the xml. This may be because I’m inexperienced with webpack, but my understand is that the entire SPA gets bundled up into a single JS file. Routing inside the SPA, through React or Mithril or whatever, can do everything I need in terms of parsing the url and preparing the correct xml to return, but it can’t return just the generated xml file. It can modify the DOM and insert the xml content into the body of the page, but that’s not what I need. Again, I have little to no experience with webpack, but afaik it’s impossible to get it to respond to a request with just plain xml, unless that xml is a static file declared in webpack.config.js, which of course it isn’t.

1 Like

But here you are calling from the command line, I believe calling that same function from within your frontend will return just the string. Even if not, you should be able to process the string to get rid of those ”candid extras”, right?

But from what you are saying it seems that it’s not that trivial and I am in no way an experienced frontend developer :slight_smile:

I’m not sure how to return “just the string” from frontend code that goes through webpack. I can access the string and process it, but then what? How do I return a page that consists of only that xml string, with no surrounding html? Maybe there’s a way; I’m new to webpack too.

At the moment, a canister cannot serve plain HTML or XML response. If you really want a plain text to be returned from a canister, you can try the proxy solution given by @nometa in another discussion thread. EDIT: just realized that thread was also a reply to your questions :slight_smile:

We are aware that serving plain HTML (or data encoded in other HTTP content type) directly from the canister end point is a popular demand. But the JSON format at the moment contains extra data besides the return value of calling a method, e.g., signature and proof that can help verify the authenticity of the return value.

1 Like