How to provide callback function to iTunes search API

416 views Asked by At

I am struggling to find a way to provide a callback function to correctly use the iTunes Store search API.

I am trying to achieve this behaviour:

const getiTunes = fetch(`https://itunes.apple.com/search?term=${search}&media=movie&limit=200`)
  .then(results => results.json())
  .then(results => {
    if (results.errorMessage) throw Error(results.errorMessage)
    else setResults(results)
  })
  .catch(error => {
    //handle error
  })

and so far I have this:

const getiTunes = results =>  {
  if (results.errorMessage) throw Error(results.errorMessage)
  else setITunes(results)
}

const script = document.createElement("script")
script.src = `https://itunes.apple.com/search?term=${search}&media=movie&limit=200&callback=getiTunes`
script.async = true
document.body.appendChild(script)

I keep getting the following error:

Uncaught ReferenceError: getiTunes is not defined

I have also tried &callback="getiTunes" and &callback=${getiTunes} and they also fail.

These functions are being called in an useEffect hook in React. Is there a specific way I have to retrieve the function name?


Aside

And if I try to not provide a callback function, it will work only if the search is a new search (ie I haven't searched that term before). However, if I have (say on production URL or locally) then it will error with the following:

Access to fetch at 'https://itunes.apple.com/search?term=spiderman&media=movie&limit=200' from origin 'http://localhost:3000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value "--it has the last URL I used to search for this successfully--"...
2

There are 2 answers

0
Charklewis On BEST ANSWER

I was able to get this working by adding my script to handle the response to the document also.

const loadItunes = document.createElement("script")
loadItunes.src = `https://itunes.apple.com/search?term=${search}&media=movie&limit=200&callback=getiTunes`
loadItunes.async = true

const handleResults = document.createElement("script")

handleResults.type = "text/javascript"
handleResults.text = "function getiTunes(response) { //function code };"

document.body.appendChild(loadItunes)
document.body.appendChild(handleResults)

Updated Answer

I have found a better solution via this code sandbox. It perfectly solves this problem by creating a function which then hands off the response to a callback function.

export const fetchJSONP = (url, callback) => {
  var callbackName = "jsonp_callback_" + Math.round(100000 * Math.random())
  window[callbackName] = function (data) {
    delete window[callbackName]
    document.body.removeChild(script)
    callback(data)
  }

  var script = document.createElement("script")
  script.src = url + (url.indexOf("?") >= 0 ? "&" : "?") + "callback=" + callbackName
  document.body.appendChild(script)
}

I then use it in the following way:

const handleResponse = response => {
  //do stuff with response
}
fetchJSONP("https://itunes.apple.com/search?term=spiderman&media=movie&limit=200", handleResponse)
1
Vignesh Rathnam On

The method you're trying is JSONP (JSON with Padding) method. We just need the external script and the a function. The external website provides a callback function for your method.

So it sends all the data in function parameter.

by mistaken you have adden } to your script url

script.src = `https://itunes.apple.com/search?term=${search}&media=movie&limit=200&callback=getiTunes}`

Eg code:

const getiTunes=results=>{
if (results.errorMessage) throw new 
Error(results.errorMessage)
  else setITunes(results)
};
const script = document.createElement("script")
script.src = `https://itunes.apple.com/search?term=bat&media=movie&limit=200&callback=getiTunes`
script.async = true
document.body.appendChild(script);
// returns getiTunes(...someData)