B Polit
B Polit

Reputation: 190

eXist-db send JSON via POST request using eXPath Http_module

I am trying to send JSON via a POST request from eXist-db to an API using the eXPath HTTP-Module, but I'm always recieving the following Error:

exerr:ERROR Error serializing the body content 

My XQuery looks like:

xquery version "3.1";

declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";

let $payload := map {
    "name": "testuser",
    "role": "user"
  }


return

hc:send-request(
  <hc:request method='post'>
    <hc:body media-type="application/json"/>
  </hc:request>,
  'https://reqres.in/api/users',
  serialize($payload, <output:serialization-parameters>
            <output:method>json</output:method>
        </output:serialization-parameters>)
)[2] => util:base64-decode() => parse-json()

Expected Output (tested via Postman):

{
    "name": "testuser",
    "id": "820",
    "createdAt": "2021-06-03T05:50:32.049Z"
}

How do i serialize content to JSON and send it via a POST-request from eXist-db? The solution prompted here is not working for me.

Upvotes: 3

Views: 525

Answers (2)

Loren Cahlander
Loren Cahlander

Reputation: 1337

Here is the reformated version with the parameters broken out into their individual variables from Joe's answer.

xquery version "3.1";

let $payload := map {
    "name": "testuser",
    "role": "user"
  }
let $request := 
    <hc:request method='post'>
        <hc:body method="text" media-type="application/json"/>
    </hc:request>

let $href := 'https://reqres.in/api/users'

let $bodies := fn:serialize($payload, map { "method": "json" })
        
return

hc:send-request($request, $href, $bodies)[2] => util:base64-decode() => parse-json()

Upvotes: 1

Joe Wicentowski
Joe Wicentowski

Reputation: 5294

The solution is to add @method="text" to the <body> element.

This attribute is documented in the EXPath HTTP Client spec, section 3.2 Serializing the request content:

The default value of the serialization method depends on the media-type: it is xml if it is an XML media type, html if it is an HTML media type, xhtml if it is application/xhtml+xml, text if it is a textual media type, and binary for any other case.

What this means is that the EXPath HTTP Client doesn't have a built-in mapping for the media-type of application/json—i.e., it falls back on binary. But JSON is a textual media type, and you've already performed the serialization of your XDM map into text via the fn:serialize() function. So you have to override the EXPath HTTP Client default of method="binary" and set method="text" on the <body> element.

The draft v2 spec, simplifies sending JSON; by default, when it detects that the body contains a map() or array(), it will serialize the item as JSON, with the appropriate media-type.

But for now with v1, we still need to explicitly (1) serialize maps and arrays using the JSON serialization method and (2) specify method="text" on the <body> element.

Upvotes: 4

Related Questions