I am working on an app and I'd like to display the events that are stored in MongoDB using my GraphQL end points. This is how I do it:
List appointments = Query(
options: QueryOptions(document: gql(_getEvents)),
builder: (result, {fetchMore, refetch}) {
if (result.isLoading) {
return const CircularProgressIndicator();
} else {
result.data!["events"];
}
throw const Text('Something happened');
}) as List;
return _DataSource(appointments);
}
However, I get an error saying that 'The type 'Query is not a subtype of type 'List' in type cast'. Apparently flutter doesn't like that I cast Query as List. The question is 'Is there a way to make the cast work'? Or is there any other applicable workaround?
Thank you in advance
Related
I,m learning MongoDB and mongoose and now I have a problem in defining a 404 status for my route handler. Here is the code:
app.get('/users/:id', async (req, res) => {
const _id = req.params.id
try {
const user = await User.findById(_id)
if (!user) {
return res.status(404).send()
}
res.send(user)
} catch (error) {
res.status(500).send()
}
})
Now if I give it an id that doesn't exist, it doesn't give me 404 Not Found status. it only executes the catch block which is not what I want.
I would appreciate it if you tell me where I made mistake or tell me a way to get error handling for that.
Thanks
The problem
As you can see in the log
CastError: Cast to ObjectId failed for value "6082d50a2c89db3164" at path "_id" for model "User"
It means : the value you provide to findById function ("6082d50a2c89db3164") is not a valid ObjectId.Then the catch block is executed.
Suggestion
1. Validate the parameter before query in database
I understand that you're trying to provide some id that doesn't exist in the database to test. But IMHO, there a difference between 2 cases :
you provide a valid id, and this id cannot be found in the database. It should return 404 in this case
you provide an invalid id in the request, it could be a string like "6082d50a2c89db3164", or even "#Q*&$(##*" or anything we could imagine. For this case, it could be better if we validate the input (req.params._id) to ensure that the format is valid. The code will be something like this:
app.get('/users/:id', async (req, res) => {
const _id = req.params.id;
// validate params
if(!isValidateObjectId(_id)) { // the function we need to write
res.status(200).send("Invalid params"); // you can define your status and message
return;
}
// good params, get user from database
try {
const user = await User.findById(_id)
if (!user) {
return res.status(404).send()
}
res.send(user)
} catch (error) {
res.status(500).send()
}
})
2. Use findOne() method instead of findById
If you want a simpler solution, don't use findById because the function expects a valid ObjectId. We can use findOne() method :
app.get('/users/:id', async (req, res) => {
const _id = req.params.id
try {
const user = await User.findOne({_id : _id})
if (!user) {
return res.status(404).send()
}
res.send(user)
} catch (error) {
res.status(500).send()
}
})
(IMHO, the first solution is better though..)
Some helpful link :
https://docs.mongodb.com/manual/reference/method/ObjectId/
Can I determine if a string is a MongoDB ObjectID?
https://mongoosejs.com/docs/api.html#model_Model.findOne
How to validate only the syntax of graphQL Query ?
My requirement is --> User wil enter a query in an editor and need to validate whether it is a graphQL valid query or not? Just syntax validation will be enough. Please suggest.
If you want validator to return boolean value, you can use this workaround:
const gql = require('graphql-tag');
const isValid = query => {
try {
gql(query);
return true;
} catch(err) {
return err;
}
};
graphql-tag parses query and if it throws an error, you just return false
I am writing an app with GraphQL and mongoose. I created a function to get all bookings inside MongoDB. A booking object contains a reference to another object called Service. When I store a booking, it will store the associated service object as an ObjectID in MongoDB. When I make a query in graphql to get all the bookings, graphql does not services and their field types since graphql only receives an objectID. How can I fix graphql?
You need to write a resolver for the serviceType in AppointmentBooking.
Query: {
async getAppointmentBookings() {
...
}
},
Mutation: {
...
},
AppointmentBooking: {
serviceType: async(parent, args, ctx, info) => {
// Here you will get the objectId from the parent that need to query services
// This will call for every object inside the bookings
// Assuming you are storing the objectID for the services in the key servicetype
const serviceId = parent.serviceType;
try {
const serviceDetails = await Sevice.findByID(serviceID) ;
return serviceDetails;
} catch (err) {
throw new Error(err);
}
}
}
I have code like this for QuerySnapshot to get documents in collection that works good.
List<DaftarHazard> _userHazardFromSnapshot(QuerySnapshot snapshot) {
return snapshot.documents.map((hazards) {
return DaftarHazard(
waktuHazard: hazards.data['waktuHazard'],
judulHazard: hazards.data['judulHazard'],
isiHazard: hazards.data['isiHazard'],
fotoHazard: hazards.data['fotoHazard'],
namaPelapor: hazards.data['namaPelapor'],
lokasiHazard: hazards.data['lokasiHazard'],
statusHazard: hazards.data['statusHazard']);
}).toList();
}
Stream<List<DaftarHazard>> get userHazardAsSuper {
return userHazards.snapshots().map(_userHazardFromSnapshot);
}
But then I need to Map DocumentSnapshot to class properties.
I don't know how to get this done.
How can I do this using the same method that I use for the QuerySnapshot?
The code above I get from collections.
Code below is the one I use to get fields in a document
Stream<List<UserDetails>> get userDetails {
return userData.document(uid).snapshots().map(_userDetailsFromSnapshot);
}
and using this to map to the properties
List<UserDetails> _userDetailsFromSnapshot(DocumentSnapshot snapshot) {
return snapshot.data.map((item) {
return UserDetails(
name: details.['name'],
email: details.data['email'],
);
}).toList();
}
But code above does not work.
Found the solutions here:
Net Ninja
You to extract the data from your DocumentSnapshot.
List<DaftarHazard> _userHazardFromSnapshot(QuerySnapshot snapshot) {
return snapshot.documents.map((hazards) {
return DaftarHazard(
waktuHazard: hazards.data['waktuHazard'] != null ? WaktuHazard.fromData(hazards.data['waktuHazard'].data) : null,
judulHazard: hazards.data['judulHazard'],
isiHazard: hazards.data['isiHazard'],
fotoHazard: hazards.data['fotoHazard'],
namaPelapor: hazards.data['namaPelapor'],
lokasiHazard: hazards.data['lokasiHazard'],
statusHazard: hazards.data['statusHazard']);
}).toList();
}
And replace each property for its own object instead of DocumentSnapshots.
I'm not sure of the structure that you want, but basically, you just need to access the data property of your DocumentSnapshot and parse it accordingly.
Found the solution for getting field and value from a specific document in firestore here
[Net Ninja][1]
I'm trying to get some data into a firestore collection from a flutter app like so:
onPressed: () {
_uid = _controller.text.trim();
Firestore.instance.collection('UserData').document(_uid)
.setData({
'uid': _uid
})
.then((_) {
print("user added to UserData");
}).catchError((e) {
print("add UserData err: $e");
});
},
But this gives the following error:
add UserData err: PlatformException(error, Invalid document reference. Document references must have an even number of segments, but UserData has 1, null)
This is weird since I have a simple coll/doc pair. I'm using the same code structure I'm multiple other places with no problem. Here's how the db looks like:
Someone please help me sort this out?
It sounds like _uid is an empty string. You'll have to figure out why that is, and check for that case before using it in a document reference.