Random quote machine "invalid token"

So I’ve revisited the Random Quote Machine, trying to build a pure-JS, class-based version (I know, it’s not showcasing front-end libraries, but it seemed like a fun idea at the time…)

It passes all the tests, most of the time. It fails if the author is anonymous (for which I can hack a solution). But there is something going on that I just can’t wrap my head around: bad characters in the feed.

I’ve set up a fetch(...).then(...).catch(...), and in the event of an error, it simply gets a new quote all over again. Sometimes the error seems to be “Invalid method call”, but the next iteration works fine. Sometimes it gives me an error "invalid token ' at position ...", which has me wondering if the feed is sending invalid JSON?

At any rate, the quote generator is running at http://surveys-and-stuff-parenttobias.codeanyapp.com/tinkering/quote-machine/index.html – any ideas or suggestions how to debug weirdness in REST calls would be great.

I get this error in the devtools: “SyntaxError: JSON.parse: bad escaped character at line 1 column 19 of the JSON data”

Checking MDN (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/JSON_bad_parse) seems to confirm that the issue lies in the JSON response

The API is sending JSON strings with single quotes escaped, so yes it’s sending invalid JSON. There is another thread about this.

Not sure if this is a good idea in general but i was interested in seeing how to clean up the JSON string so i came up with this. It just has an intermediate step where we get the text and run a replace on it before running JSON.parse(). In the few tests I ran it seemed to work just fine.

I have condensed it down here:

fetch(URL)
.then(res => res.text())
.then(text => {
  console.log(text); // Text before replace
  const noEscapes = text.replace(/\\/g, '');
  console.log(noEscapes); // Text after replace
  return JSON.parse(noEscapes);
})
.then(response => {
  ....
})

Log example on a API request:

{"quoteText":"Don\'t compromise yourself. You are all you\'ve got.", "quoteAuthor":"Janis Joplin", "senderName":"", "senderLink":"", "quoteLink":"http://forismatic.com/en/22c408ed5e/"}
{"quoteText":"Don't compromise yourself. You are all you've got.", "quoteAuthor":"Janis Joplin", "senderName":"", "senderLink":"", "quoteLink":"http://forismatic.com/en/22c408ed5e/"}

Full quote.js just in case (logs are in but commented out).

Summary
class Quote {
  constructor(props) {
    let corsProxyUrl = 'https://cors-anywhere.herokuapp.com/';
    this._props = props;
    this._quotesUrl =
      corsProxyUrl +
      'https://api.forismatic.com/api/1.0/?method=getQuote&format=json&lang=en';
    this._el = document.createElement('div');
    this._el.classList.add('quote-machine');
    this._quoteEvent = new Event('quote.success');
  }
  get domEl() {
    return this._el;
  }
  getQuote() {
    fetch(this._quotesUrl, {
      method: 'get',
      cache: 'no-cache'
    })
      .then(res => res.text())
      .then(text => {
        //console.log(text);
        const noEscapes = text.replace(/\\/g, '');
        //console.log(noEscapes);
        return JSON.parse(noEscapes);
      })
      .then(response => {
        this._text = response.quoteText;
        this._author = response.quoteAuthor;

        this._el.innerHTML = `<span id="text" class="quote-text">${
          this._text
        }</span><span id="author" class="quote-author">${this._author}<span>`;
        this._el.dispatchEvent(this._quoteEvent);
        return response.quoteText;
      })
      .catch(error => {
        this.getQuote();
        console.error('Error: ', error);
        return false;
      });
  }
  get quote() {
    return this._text;
  }
  get author() {
    return this._author;
  }
}