Jon
Jon

Reputation: 87

Why am I getting an Error 422 "query must be provided" with React Movie App?

Using The Movie Database API, my app searches movies by title and also generates movies by selected genres. Even when I successfully search for titles and genres I get an error 422 "query must be provided." When I refresh the page random movies render for a second and then disappear waiting for my query. I am thinking there may be something wrong with my dependencies [query,genre] in my useEffect. I am new to React so in fear of not posting a section that may be the culprit I will post my full App.js file. Here is the code:

function App() {
  const [search, setSearch] = useState("");
  const [query, setQuery] = useState("");
  const [movies, setMovies] = useState([]);
  const [genre, setGenre] = useState("");

  const API_KEY = "APIKEY";

  useEffect(() => {
    async function fetchMovies() {
      const response = await fetch(
        `https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&page=2&include_adult=false&query=${query}`
      );
      const data = await response.json();
      const moviesWithOnlyPosters =
        data.results &&
        data.results.filter(item => (item.poster_path != null ? item : null));
      setMovies(moviesWithOnlyPosters);
    }

    async function fetchGenres() {
      const response = await fetch(
        `https://api.themoviedb.org/3/discover/movie?api_key=${API_KEY}&sort_by=popularity.desc&include_adult=false&include_video=false&page=2&with_genres=${genre}`
      );
      const data = await response.json();
      console.log(data);
      const moviesWithOnlyPosters =
        data.results &&
        data.results.filter(item => (item.poster_path != null ? item : null));
      setMovies(moviesWithOnlyPosters);
    }
    fetchMovies();
    fetchGenres();
  }, [query, genre]);

  function updateSearch(e) {
    setSearch(e.target.value);
  }

  function getQuery(e) {
    e.preventDefault();
    setQuery(search);
    setSearch("");
  }

  function handleGenreChange(e) {
    setGenre(e.target.value);
  }

  return (
    <div className="App">
      <h1 className="app-title">What 2 Watch</h1>
      <form onSubmit={getQuery}>
        <Container fluid={true}>
          <Row>
            <Col xs="12" sm="6" className="search-bar-col">
              <input
                className="search-bar"
                type="text"
                placeholder="Search Title..."
                value={search}
                onChange={updateSearch}
              />

              <button className="search-button" type="submit">
                Search
              </button>
            </Col>

            <Col xs="12" sm="6" className="genre-dropdown-col">
              <select
                className="genre-dropdown"
                onChange={handleGenreChange}
                value={genre}
              >
                <option hidden>Find by Genre</option>
                <option value="28">Action</option>
                <option value="12">Adventure</option>
                <option value="16">Animation</option>
                <option value="35">Comedy</option>
                <option value="99">Documentary</option>
                <option value="14">Fantasy</option>
                <option value="36">History</option>
                <option value="27">Horror</option>
                <option value="9648">Mystery</option>
                <option value="10749">Romance</option>
                <option value="878">Science Fiction</option>
                <option value="53">Thriller</option>
                <option value="10752">War</option>
                <option value="37">Western</option>
              </select>
            </Col>
          </Row>
        </Container>
      </form>

      <Row>
        {movies &&
          movies.map(item => (
            <Col xs="12" md="6" lg="4" key={item.id}>
              <Movie
                key={item.id}
                title={item.title}
                year={item.release_date}
                image={item.poster_path}
                description={item.overview}
              />
            </Col>
          ))}
      </Row>
    </div>
  );
}

export default App;

Upvotes: 0

Views: 1198

Answers (1)

subashMahapatra
subashMahapatra

Reputation: 6837

The reason for the error is the component App is rendered with the default state value of query on the first render. Because the state value of query is initialized as an empty string(""), the first time the App component renders there is no query to search for so the fetch call inside fetchMovies is called with a URL value of,

"https://api.themoviedb.org/3/search/movie?api_key=your-api-key&page=2&include_adult=false&query="

Which results to 422 unknown because no query was provided in the URL .

Solution

Make the fetch call to the API only if the is query value exists. The same logic can be applied if the fetchGenres call if it also fails with 422 unknown error.

I also suggest that you provide the query value as an argument to the function fetchMovies and include a try...catch block in the function to better handle the error cases when the API call fails.

async function fetchMovies(queryValue) {
   if (!queryValue) {
      return 
   }

   try {
     const response = await fetch(
       `https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&page=2&include_adult=false&query=${query}`
     );

     // rest of your state related logic

   } catch(error) {
     // handle the error

   }
}

Keep in mind when invoking the function pass the state variable query as argument to the function fetchMovies

fetchMovies(query)

Upvotes: 1

Related Questions