I'm currently working on an airbnb clone and I wanted to start my local server through npm run dev and it gave me the following error. I'm sot sure why this morning everything was working perfectly but now it doesn't anymore even though I did not change or do anything. I searched online and people say the response might be html instead of json but how would that happen all of a sudden?? I also got a deployed version that you can access here https://airbnb-smoky-six.vercel.app https://airbnb-smoky-six.vercel.app It would be great if someone could guide me through fixing it.
The file refers to contains the following code:
import Head from 'next/head'
import Image from 'next/image'
import Header from '../Components/Header.js'
import Banner from '../Components/Banner.js'
import styles from '../styles/Home.module.css'
import SmallCard from '../Components/SmallCard.js'
import MediumCard from '../Components/MediumCard.js'
import LargeCard from '../Components/LargeCard.js'
import Footer from '../Components/Footer.js'
export default function Home({exploreData, cardsData}) {
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<Header />
<Banner />
<main className='max-w-6xl mx-auto px-12 sm:px-16'>
<section className='pt-6'>
<h2 className='text-4xl font-semibold pb-5'>Explore Nearby</h2>
{/* Pull name from a server - API endpoints */}
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 '>
{exploreData?.map(({img, distance, location}) => (
<SmallCard
key={img}
img={img}
distance={distance}
location={location}
/>
))}
</div>
</section>
<section>
<h2 className='text-4xl font-semibold py-8'>Live Anywhere</h2>
{/* pull data from API endpoints */}
<div className='flex space-x-3 overflow-scroll scrollbar-hide p-3 -ml-3'>
{cardsData?.map(({ img, title }) => (
<MediumCard
key={img}
img={img}
title={title}
/>
))}
</div>
</section>
<section>
<LargeCard
img="https://links.papareact.com/4cj"
title="The Greatest Outdoors"
description="Wishlist curated by Airbnb"
buttonText="Get Inspired"
/>
</section>
</main>
<Footer />
</div>
)
}
export async function getStaticProps() {
const exploreData = await fetch('https://links.papareact.com/pyp')
.then (
(res) => res.json()
);
const cardsData = await fetch('https://links.papareact.com/zp1')
.then (
(res) => res.json()
);
return{
props: {
exploreData,
cardsData,
},
};
}
CodePudding user response:
You suddenly got the error because the server didn't respond JSON data. It can be server error (500) or client bad data (4xx). Either reasons, your clients should be able to catch the error. If the response status is not OK (2xx HTTP status code), then you throw error instead of trying to parse JSON
res.json()
There is a good example documentation at this
Your logic can be rewritten as bellow:
export async function getStaticProps() {
const exploreDataResponse = await fetch('https://links.papareact.com/pyp');
if (!exploreDataResponse.ok) {
// Throw error or handle logic when failed to fetch exploreData here
}
const exploreData = exploreDataResponse.json();
const cardsDataResponse = await fetch('https://links.papareact.com/zp1');
if (!cardsDataResponse.ok) {
// Throw error or handle logic when failed to fetch cardData here
}
const cardsData = cardsDataResponse.json();
return {
props: {
exploreData,
cardsData,
},
};
}
Note: Depend on your application business to decide the data and error handling flow.
CodePudding user response:
When you call fetch()
, it returns a promise that resolves with a Response type. That response has a body that contains some text.
If you are sure the text is formatted in JSON, you can call the res.json()
and it should return a promise resolved with the parsed value from the body.
However if the response text had some problem in the formatting of JSON (or didn't even include JSON at all), then you get the problem mentioned in your question.
Assuming the API you are trying to reach cannot guarantee you the response will always be a string formatted in JSON, you should handle the SyntaxError yourself:
const responseText = await res.text()
let responseValue
try {
responseValue = JSON.parse(responseText)
}
catch (error) {
// Failed to parse JSON from the response text
// Need to handle it somehow. In this example,
// I simply let it be the plain text string
responseValue = responseText
}
You should also think about this: making a request is not always going to be successful. Maybe you do not have an Internet connection. Maybe you do, but your server sends a response that is not successful. In that case you should also handle the unsuccessful cases. One simple way of doing that is checking the response object:
if (res.ok) {
// The value resolved from the fetch() call is a Response object
// and you can use .ok to check if the status code fell within the 2XX range
// In which case it means it was successful.
// Proceed as normal here
// e.g. ... await res.text(), then parse JSON.
}
else {
// The response status code fell outside 2XX range,
// so something might have gone wrong.
// Handle that case here
}
You can reference the documentation on MDN for that and other useful properties.