Search code examples
javascriptnode.jsfetchecmascript-2016

Get payload that caused json parse error in Fetch


I have the following code for making POST Requests. I'm not 100% sure about error handling here, but it was important for me that I get body text when request is not successful.

One issue that I still do have is - if server responds with 200 OK but invalid json - can I log that payload? What would be the correct way of logging for Fetch?

           Fetch(data.notificationUrl, {
                method: 'POST',
                body: post_data,
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then((res) => {

                if (!res.ok) {
                    // Could reject the promise here but than response text wouldn't be available
                    //return Promise.reject(`Response was not OK. Status code: ${res.status} text: ${res.statusText}`);
                    return res.text().then((txt) => `Response was not OK. Status code: ${res.status} text: ${res.statusText}.\nResponse: ${txt}`);
                }
                // response ok so we should return json, could follow https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch and determine the payload type by content-type header...
                return res.json();
            }).then((response) => {

                if (response) {
                    // set result
                    // ...

                    // redirect
                    return reply.redirect(data.redirectUrlDirectory);
                }

                return reply(Boom.preconditionFailed(`Did not reply with correct payload! json:'${JSON.stringify(response)}'`));
            }).catch((err) => {

                return reply(Boom.badData(`Could not notify on url ${data.notificationUrl} about the payment ${id}.\nError: "${err}"`));
            });

Solution

  • I would use something like this.

    This fist option asumes your service response always the header "application/json" and a the pay load simple text which I mock it like this.

    var app = new express();
    app.get('/valid', function(req, res){
      res.json({ok: "ok"});
    });
    app.get('/invalid', function(req, res){
      res.json("bad json body");
    });
    

    and the fetch json handling should looks like this. The other part of your code looks like good for me.

    var response2 = res.clone();
    return res.json().then((json) => {
        // log your good payload
        try {
          // here we check json is not an object
          return typeof json === 'object' ? json : JSON.parse(json);
        } catch(error) {
           // this drives you the Promise catch
          throw error;
        }    
    }).catch(function(error) {
         return response2.text().then((txt) => `Response was not OK. Status code: ${response2.status} text: ${response2.statusText}.\nResponse: ${txt}`);
        //this error will be capture by your last .catch()
    });
    

    xxx.clone() allows you to resolve multiple times the same response and create your own combinations like the previous one.