2

Im beginner and trying to better understand API calls.

I want to make a call to a bible api that retrieves all books. I then need to make a call to the same api with the book # to retrieve all chapters for requested book.

I then want to display a list of the books along with the chapters.

To this I made a utility function that loops through the books and returns the chapters. This is where it breaks.

I was able to retrieve the books and display them. But I am stuck as to how the make the second API call. I keep getting an error that I cannot serialize object Promise.

Also what is the best way to console log here in Next? Im not sure how to go about seeing what its being returned.

Here is what I have so far:

export default function Home(props) {
  console.log(props);
  return (
    <div className="container">
      <div>{/** display books & chapters */}</div>
    </div>
  );
}

export async function getStaticProps() {
  // get all books
  const reqBooks = await fetch(`https://getbible.net/v1/web/books.json`);
  const resBooks = await reqBooks.json();
  // convert to array of objs
  const books = await Object.entries(resBooks);


  const chapters = await getChapters(books);

  return {
    props: {
      books,
      chapters,
    },
  };
}

// utility... loop through books and make api calls to get chapters for each book
async function getChapters(books) {
  const chaptersArr = [];

  books.map((item, idx) => {
    //
    let url = item[1].url;
    let bookChapters = fetch(url).then(response => response.json().then(data => data));
    arr.push(bookChapters);
  });
  return chaptersArr;
}
VLAZ
  • 26,331
  • 9
  • 49
  • 67
underhook
  • 55
  • 2
  • 6

1 Answers1

4

The problem is that you're pushing promises into an array, not the values inside the promises. Instead of using that array, you can return in the map directly, and use Promise.all to get the values out. (You could use the array too, but there's no need for it since you're using a map). I lifted the getBooks call into its own function for clarity here, but the important change is what's going on in getChapters in the map:

async function getBooks () {
  const res = await fetch('https://getbible.net/v1/web/books.json')
  const json = await res.json()
  return Object.entries(json)
}

async function getChapters (books) {
  const chapters = await Promise.all(
    books.map(async (item) => {
      const url = item[1].url
      const res = await fetch(url)
      const json = await res.json()
      return json
    })
  )

  return chapters
}

export async function getStaticProps() {
  const books = await getBooks()
  const chapters = await getChapters(books)

  return {
    props: {
      books,
      chapters,
    },
  }
}

You can test this in plain Node (assuming node-fetch or a similar package) or the browser outside of Next with something like:

getStaticProps().then(data => {
  console.log(JSON.stringify(data, null, 2))
})
Zac Anger
  • 6,983
  • 2
  • 15
  • 42