Hello everyone! I'm porting an old java servlet application (yay 😅) to clojure with reitit. For all of the JSON based endpoints it's been truly only pleasure and joy! (Thanks for awesome project!!) On the other hand i have to implement a single XML based route that takes in an XML document from the request body, enriches it and returns the enriched document as response body. I saw something here about returning xml https://github.com/metosin/reitit/blob/master/doc/ring/content_negotiation.md but not much else. Does anyone have some pointers or snippets that may help me? Thanks in advance! (i have tried discussing this with various gpts but i feel they are leading my astray)
you can return xml by having your handler output something like
{:status 200
:body ""
:headers {"Content-Type" "application/xml"}}
edit: application/xml of course!the reitit/muuntaja magic only happens if your :body is a clojure map, muuntaja can then convert that to json, edn, transit, etc. depending on the Accept headers in the request
similarly, muuntaja won't decode an XML request body for you, you'll just get it as a string
I've done XML before for mastodon (webfinger) interop example of it being used with reitit https://github.com/valerauko/kitsune/blob/f052a5027d2207cbb357fcd74328d6c47e0a0631/api/src/kitsune/well_known/routes.clj muuntaja formatter: https://github.com/valerauko/kitsune/blob/f052a5027d2207cbb357fcd74328d6c47e0a0631/api/src/kitsune/format/xml.clj
@joel.kaasinen and @vale thanks both for your time! @joel.kaasinen i think in your solution the output would be an xml string but with "" around, so this would not interop with xml logic. @vale i think this is exactly the kind of pattern I was looking for thanks so much i'll dig into it ❤️
what's "the output"? if you give a string to :body, the contents of that string will be the contents of the HTTP response, without any formatting
Lying about the content-type is not a good practice though
I'm sorry I'm not following you
an example:
You had application/json for xml content
route definition:
(def routes
["/plain"
["/foo" {:get {:handler (fn [req]
{:status 200
:headers {"content-type" "application/xml"}
:body "<xml></xml>"})}}]])
curl:
% curl -v
* Trying 127.0.0.1:3000...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /plain/foo HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.83.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Wed, 05 Mar 2025 14:34:08 GMT
< Content-Type: application/xml
< Transfer-Encoding: chunked
< Server: Jetty(11.0.20)
<
* Connection #0 to host localhost left intact
<xml></xml> oh yeah sorry, that was a very confusing typo from me facepalm 🤦
I meant application/xml, not sure what went into my fingers
anyway, my point is that if you have a single xml endpoint, you can just bypass the muuntaja & reitit stuff like this. if you have a lot of xml stuff then you probably want some middleware that converts between xml and clojure data, like in valerauko's example.
Great thank again to you both 🙂