I have a condition call. To check condition you need to call other endopint. What is better api design?
e.g
if(fetch('api/is-data-valid')){
const data = fetch('api/get-profile-data');
// do something with data
}
or
const data = fetch('api/get-profile-if-data-valid');
if(data.isDataValid) {
// do something with data
}
If the client can't work out whether the data is valid, the API should respond accordingly, without an extra step.
Instead of checking api/is-data-valid to get api/get-profile-data, do it in one request, which hides the implementation suggested by api/get-profile-if-data-valid
You can only get profile-data if the data is valid so let the API work it out.
fetch('api/get-profile-data'); // returns profile data or 404
and let the client concentrate on displaying an error saying the data is invalid because the corresponding profile doesn't exist.
The answer depends on a few things. In general it's best to keep the number of api calls to a minimum so doing one call instead of two is preferable. However if there are cases that someone would want to check if data is valid without getting the profile, then having the is-data-valid api is important.
My advice would be to have both api's but allow someone to call get-profile-data when it's invalid and handle that case in a well defined way. This would allow the work to be done with a single call, but still allow other use cases where checking the data validity is useful on its own.
Related
So I'm having an issue with my create method in my angular. I'm using django for my backend, and I doublechecked, everything is working in the backend, with postman. Anyways here's the error. When I try to make a post request, this is the error that I get in the console. Below oyu may find the product that is sent from my end.
Note: This may not be the ideal approach to the overall problem, but it does answer the immediate question at hand.
As the error states you need to pass in an array (irrespective of how many categories are selected) rather than a string. Make the following change:
onSubmit() {
const formValues = Object.assign({}, this.productForm.value);
productForm["product_category"] = productForm["product_category"]
.split(',').map(e => e.trim());
}
Here, the product_category from formValues is fetched and the string is split based on , which results in an array - to which empty spaces are removed and assigned back as the new value to product_category.
I am relatively new to Meteor, and I'm trying to create a web store for my sister-in-law that takes data from her existing Etsy store and puts a custom skin on it. I've defined all of my Meteor.methods to retrieve the data, and I've proofed the data with a series of console.log statements... So, the data is there, but it won't render on the screen. Here is an example of some of the code on the server side:
Meteor.methods({
...
'getShopSections': function() {
this.unblock();
var URL = baseURL + "/sections?api_key="+apiKey;
var response = Meteor.http.get(URL).data.results;
return response;
}
...
});
This method returns an array of Object. A sample bit of JSON string from one of the returned Objects from the array:
{
active_listing_count: 20,
rank: 2,
shop_section_id: 1******0,
title: "Example Title",
user_id: 2******7
}
After fetching this data without a hitch, I was ready to make the call from the client side, and I tried and failed in several different ways before a Google search landed me at this tutorial here: https://dzone.com/articles/integrating-external-apis-your
On the client side, I have a nav.js file with the following bit of code, adapted from the above tutorial:
Template.nav.rendered = function() {
Meteor.call('getShopSections', function(err, res) {
Session.set('sections', res);
return res;
});
};
Template.nav.helpers({
category: function() {
var sections = Session.get('sections');
return sections;
}
});
And a sample call from inside my nav.html template...
<ul>
{{#each category}}
<li>{{category.title}}</li>
{{/each}}
</ul>
So, there's a few things going on here that I'm unsure of. First and foremost, the DOM is not rendering any of the category.title String despite showing the appropriate number of li placeholders. Secondly, before I followed the above tutorial, I didn't define a Session variable. Considering that the list of shop categories should remain static once the template is loaded, I didn't think it was necessary from what I understand about Session variables... but for some reason this was the difference between the template displaying a single empty <li> tag versus a number of empty <li>'s equal to category.length --- so, even though I can't comprehend why the Session variable is needed in this instance, it did bring me one perceived step closer to my goal... I have tried a number of console.log statements on the client side, and I am 100% sure the data is defined and available, but when I check the source code in my Developer Tools window, the DOM just shows a number of empty li brackets.
Can any Meteor gurus explain why 1) the DOM is not rendering any of the titles, and 2) if the Session variable indeed necessary? Please let me know if more information is needed, and I'll be very happy to provide it. Thanks!
You set the data context when you use #each, so simply use:
<li>{{title}}</li>
If a Session is the right type of reactive variable to use here or not is hard to determine without knowing what you are doing but my rough guess is that a Mini Mongo collection may be better suited for what it appears you are doing.
To get you started on deciding the correct type of reactive variable to use for this head over to the full Meteor documentation and investigate: collections, sessions, and reactive vars.
Edit: To step back and clarify a bit, a Template helper is called a reactive computation. Reactive computations inside of helpers will only execute if they are used in their respective templates AND if you use a reactive variable inside of the computation. There are multiple types of reactive variable, each with their own attributes. Your code likely didn't work at all before you used Session because you were not using a reactive variable.
UPDATE 1: 5 votes have been received, so I have submitted a feature request: https://github.com/LearnBoost/mongoose/issues/2637
Please cast your +1 votes there to let the core team know you want this feature.
UPDATE 2: See answer below...
ORIGINAL POST:
Lets say I do a "lean" query on a collection OR receive some data from a REST service and I get an array of objects (not mongoose documents).
These objects already exist in the database, but I need to convert some/all of those objects to mongoose documents for individual editing/saving.
I have read through the source and there is a lot going on once mongoose has data from the database (populating, casting, initializing, etc), but there doesn't seem to be a method for 'exposing' this to the outside world.
I am using the following, but it just seems hacky ($data is a plain object):
// What other properties am I not setting? Is this enough?
var doc = new MyModel( $data );
doc.isNew = false;
// mimicking mongoose internals
// "init" is called internally after a document is loaded from the database
// This method is not documented, but seems like the most "proper" way to do this.
var doc = new MyModel( undefined );
doc.init( $data );
UPDATE: After more searching I don't think there is a way to do this yet, and the first method above is your best bet (mongoose v3.8.8). If anybody else is interested in this, I will make a feature request for something like this (leave a comment or upvote please):
var doc = MyModel.hydrate( $data );
Posting my own answer so this doesn't stay open:
Version 4 models (stable released on 2015-03-25) now exposes a hydrate() method. None of the fields will be marked as dirty initially, meaning a call to save() will do nothing until a field is mutated.
https://github.com/LearnBoost/mongoose/blob/41ea6010c4a84716aec7a5798c7c35ef21aa294f/lib/model.js#L1639-1657
It is very important to note that this is intended to be used to convert a plain JS object loaded from the database into a mongoose document. If you are receiving a document from a REST service or something like that, you should use findById() and update().
For those who live dangerously:
If you really want to update an existing document without touching the database, I suppose you could call hydrate(), mark fields as dirty, and then call save(). This is not too different than the method of setting doc.isNew = false; as I suggested in my original question. However, Valeri (from the mongoose team) suggested not doing this. It could cause validation errors and other edge case issues and generally isn't good practice. findById is really fast and will not be your bottleneck.
If you are getting a response from REST service and say you have a User mongoose model
var User = mongoose.model('User');
var fields = res.body; //Response JSON
var newUser = new User(fields);
newUser.save(function(err,resource){
console.log(resource);
});
In other case say you have an array of user JSON objects from User.find() that you want to query or populate
var query = User.find({});
query.exec(function(users){
//mongoose deep-populate ref docs
User.deeppopulate users 'email_id phone_number'.exec({
//query through populated users objects
});
});
MongoDB doesn't support Joins and Transfers. So for now you can't cast values to an object directly. Although you can work around it with forEach.
I'm trying to get the number of results of the Ember Data Store filter. E.g
var users = this.store.filter('relevantUser', function(user)
{
return user.get('screenName') == screenName;
});
return user.get('length');
But this always seems to return 0. What am I doing wrong?
I think it should be users.get('length');.
Things to make sure when using filter method of the store.
First argument is the model type. Assuming you have a model named App.RelevantUser then your query is fine, else if the model is App.User then you should be using 'user'.
The var users is actually a DS.PromiseArray instance and not an array actually. Try doing this
this.store.filter('relevantUser',function(user){return user.get('screenName')==screenName}).then(function(relevantUsers){console.log(relevantUsers.get('length'))})
As store.filter queries the server too we need to wait for the promise to resolve before accessing the results. Otherwise they would be always 0.
Incase you are using Chrome. Open up Network Tab in Dev Tools and check the network request going to the server when you run the filter query.
I'm working on a large AngularJS app in which I am trying to encapsulate all my Ajax code into various services which the controllers get data from. The problem revolves around needing to know the status of any ajax calls and displaying the correct information to the user. There could be no data found, data currently loading, or an error that has occurred preventing data from being loaded. The user needs to be shown a loading message, a "no data found" message, or an error message.
Let's say I have a ProjectService. Ideally if there was a method called getAllProjects it would return an array of projects. But that way I have no idea what is happening with the server communication.
So how to I let the controller know if data is loaded, loading, or an error has occurred? The best way I can come up with is using callbacks like in the pseudo code below. Is there any better way to accomplish such a thing or anything I may be overlooking?
Thanks.
app.controller( "ProjectController", function( $scope, ProjectService ){
// Set the initial / default status
$scope.loadStatus = "loading";
// Return an empty array initially that will be filled with
// any data that is returned from the server
// The callback function will be executed when the ajax call is finished
$scope.projects = ProjectService.getProjects(function( status ){
// Alert the controller of a status change
setStatus( status );
});
function setStatus( ){
$scope.loadStatus = status;
// ... update the view or whatever is needed when the status changes....
}
});
app.service( "ProjectService", function( $resource ){
return {
getAllProjects: function(){
// ... load and return the data from the server ...
}
};
});
In our codebase we've just been doing
$scope.flags.loading = true;
$http(...).success(function(){
$scope.flags.loading = false;
});
Yes, this is sort of simplistic, but not all queries require a loading overlay (such as during pagination or refreshing). This is why we have opted not to simply use a decorator.
However, lets say you want to, I can think of a few ways of doing this. Lets say you're like us and keep your flags together in an object. Then you can use associations to your advantage:
MyService.flags = $scope.flags
... (inside the service) ...
this.flags.loading = true/false;
By establishing a reference as a property of the service, you can do all the state toggling from within the service, and avoid cluttering your controller. Again though, this might create the possible drawback of having 2 or more close-together queries conflicting (first query finishes and removes the loading state before the second one completes).
For this reason we have been find with setting the flag. We don't really check for 'loaded' we just check for data or use success callbacks.