Technologies:
Tolerim
a month ago
In Apollo GraphQL resolver, encountering undefined properties cannot be read.
I am following the instructions from an Apollo guide to generate a basic query that includes filters. However, I encountered an error message in the sandbox response stating, "TypeError: Cannot read properties of undefined (reading 'liked')" which stems from the fact that 'liked' is a field in my dataset. I conducted some tests by modifying the type definition and query with other properties, but the same error persists. Below are snippets of my codebase for reference:
The index.js file instantiates a new ApolloServer using typeDefs and resolvers:
// index.js
const { ApolloServer } = require("apollo-server");
const { typeDefs } = require("./schema/type-defs");
const { resolvers } = require("./schema/resolvers");
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`YOUR API IS RUNNING AT: ${url} :)`);
});
The FakeData.js file contains my dataset, MovieList:
// FakeData.js
const MovieList = [
{
id: 1,
name: "Avengers Endgame",
year: 2019,
liked: true,
},
{
id: 2,
name: "Interstellar",
year: 2007,
liked: true,
},
{
id: 3,
name: "Superbad",
year: 2007,
liked: true,
},
{
id: 4,
name: "Madagascar 12",
year: 2073,
liked: false,
},
];
module.exports = { MovieList };
The type-defs.js file defines the schema for the Movie type, input types for filters, and a query type to retrieve Movie records:
// type-defs.js
const { gql } = require("apollo-server");
const typeDefs = gql`
type Movie {
id: ID!
name: String!
year: Int!
liked: Boolean!
}
input MovieFilters {
liked: Boolean!
year: Int!
}
input MovieInput {
filter: MovieFilters
}
type Query {
movie(id: ID!): Movie
movies(input: MovieInput): [Movie]!
}
`;
module.exports = { typeDefs };
The resolvers.js file contains the resolver to filter Movie records based on the specified criteria (applied through filter object param):
// resolvers.js
const { MovieList } = require("../FakeData");
const _ = require("lodash");
const resolvers = {
Query: {
movies: (parent, args) => {
const { filter } = args;
const shouldApplyFilters = filter !== null;
let movies = MovieList;
if (!shouldApplyFilters) return movies;
const shouldApplyLikedFilter = filter.liked !== null;
const shouldApplyYearFilter = filter.year !== null;
if (shouldApplyLikedFilter) {
movies = movies
.filter((a) => a.liked === filter.liked)
}
if (shouldApplyYearFilter) {
movies = movies
.filter((a) => a.year === filter.year)
}
return movies;
},
}
};
module.exports = { resolvers };
Lastly, the query includes variables and a query structure for retrieving Movie records by applying filter criteria:
// query
query GetMoviesByFilter($input: MovieInput) {
movies(input: $input) {
id
name
liked
year
}
}
I will greatly appreciate any input you can provide on how to overcome this challenge. Thanks in advance!Answers(2)
Vogi
a month ago
Verified Answer
It seems like the error message you are receiving is due to the fact that the 'liked' field is not defined in the input object. You can try modifying the MovieFilters input type to include an optional 'liked' field as shown below:
input MovieFilters {
liked: Boolean
year: Int!
}
This will allow you to pass in a filter object that includes the 'liked' field. You can also modify the resolver function to check if the 'liked' field exists in the filter object before applying it as a filter. Here's an example:
if (shouldApplyLikedFilter && filter.hasOwnProperty('liked')) {
movies = movies.filter((a) => a.liked === filter.liked);
}
I hope this helps! Let me know if you have any other questions.Tolerim
a month ago
The problem with the provided code might be because of the following reasons:
- The filter object might be null, but it's being used as if it has liked and year properties. You can fix that by adding a null check, like if (!filter) return movies;.
- In the filter object, the liked and year properties are being set as mandatory (using the ! modifier). If you want those properties to be optional, you can remove the modifier.
- There's an error in the way the filter is being applied. Instead of checking if the liked and year properties are null, you should check if they are not undefined.
Here's an updated version of the movies resolver that should work correctly:
const resolvers = {
Query: {
movies: (parent, args) => {
const { filter } = args;
let movies = MovieList;
if (!filter) return movies;
const { liked, year } = filter;
if (liked !== undefined) {
movies = movies.filter((a) => a.liked === liked);
}
if (year !== undefined) {
movies = movies.filter((a) => a.year === year);
}
return movies;
},
},
};
With these modifications, the query should execute correctly and filter the movies based on the provided criteria.