Cómo verificar si la respuesta de una búsqueda es un objeto json en javascript

94

Estoy usando fetch polyfill para recuperar un JSON o texto de una URL, quiero saber cómo puedo verificar si la respuesta es un objeto JSON o es solo texto

fetch(URL, options).then(response => {
   // how to check if response has a body of type json?
   if (response.isJson()) return response.json();
});
Sibelius Seraphini
fuente

Respuestas:

163

Puede verificar el content-typede la respuesta, como se muestra en este ejemplo de MDN :

fetch(myRequest).then(response => {
  const contentType = response.headers.get("content-type");
  if (contentType && contentType.indexOf("application/json") !== -1) {
    return response.json().then(data => {
      // process your JSON data further
    });
  } else {
    return response.text().then(text => {
      // this is text, do something with it
    });
  }
});

Si necesita estar absolutamente seguro de que el contenido es JSON válido (y no confía en los encabezados), siempre puede aceptar la respuesta como texty analizarla usted mismo:

fetch(myRequest)
  .then(response => response.text())
  .then(text => {
    try {
        const data = JSON.parse(text);
        // Do your JSON handling here
    } catch(err) {
       // It is text, do you text handling here
    }
  });

Async / await

Si está usando async/await, podría escribirlo de una manera más lineal:

async function myFetch(myRequest) {
  try {
    const reponse = await fetch(myRequest); // Fetch the resource
    const text = await response.text(); // Parse it as text
    const data = JSON.parse(text); // Try to parse it as json
    // Do your JSON handling here
  } catch(err) {
    // This probably means your response is text, do you text handling here
  }
}
nils
fuente
1
Con la misma estrategia, puede usar response.json en combinación con catch; si detecta un error, significa que no es json. ¿No sería esa una forma más idiomática de manejar esto (en lugar de deshacerse de response.json)?
Wouter Ronteltap
3
@WouterRonteltap: ¿No se te permite hacer solo uno u otro? Parece que recuerdo que solo tienes una oportunidad de responder cualquier cosa (). Si es así, JSON es texto, pero el texto no es necesariamente JSON. Por lo tanto, primero debe hacer lo seguro, que es .text (). Si primero hace .json () y falla, no creo que tenga la oportunidad de hacer también .text (). Si me equivoco, muéstrame algo diferente.
Lonnie Best
2
En mi opinión, no puede confiar en los encabezados (aunque debería hacerlo, pero a veces simplemente no puede controlar el servidor en el otro lado). Así que es genial que también menciones try-catch en tu respuesta.
Jacob
2
Sí, @Lonnie Best tiene toda la razón en esto. si llama a .json () y arroja una excepción (porque la respuesta no es json), obtendrá una excepción "El cuerpo ya se ha consumido" si posteriormente llama a .text ()
Andy
2

Puede hacer esto limpiamente con una función auxiliar:

const parseJson = async response => {
  const text = await response.text()
  try{
    const json = JSON.parse(text)
    return json
  } catch(err) {
    throw new Error("Did not receive JSON, instead received: " + text)
  }
}

Y luego úsalo así:

fetch(URL, options)
.then(parseJson)
.then(result => {
    console.log("My json: ", result)
})

Esto arrojará un error para que pueda catchhacerlo si lo desea.

larskarbo
fuente
1

Utilice un analizador JSON como JSON.parse:

function IsJsonString(str) {
    try {
        var obj = JSON.parse(str);

         // More strict checking     
         // if (obj && typeof obj === "object") {
         //    return true;
         // }

    } catch (e) {
        return false;
    }
    return true;
}
Rakesh Soni
fuente