Random quote machine "invalid token"

Random quote machine "invalid token"
0

#1

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.


#2

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


#3

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;
  }
}