How can I get all the remote method and end-point/properties of a model in loopback 3? - loopbackjs

I am trying to find out all the remote method of model and its end-point/properties ? How can I get it in loopback 3 ?

There are similar discussions on github:
get all remote methods for managing permission
List remote methods added by relations
Below is the code they recommend to use to get all the remote methods for a particular model:
function getActiveRemoteMethods(model) {
const activeRemoteMethods = model.sharedClass
.methods({ includeDisabled: false })
.reduce((result, sharedMethod) => {
Object.assign(result, {
[sharedMethod.name]: sharedMethod.isStatic,
});
return result;
}, {});
return activeRemoteMethods;
}

Related

Graphene Django and react-router-relay

I'm having real trouble figuring out the way that Graphene Django should be used with react-router-relay. Let's say I can use the following GraphQL query fine via the GraphiQL console on my Django server:
query {
allThreads {
edges {
node {
id
}
}
}
}
This is presumably Graphene's alternative to the commmon viewer wrapper used because Relay doesn't support connections on root queries. So I understand that allThreads is really a node (of type ThreadNodeConnection), and has an edges connections that I can query.
The trouble is I can't figure out how to use this with Relay, and specifically react-router-relay. I have a React view with a fragment on it like this (with a child Thread component elsewhere):
fragments: {
store: () => Relay.QL`
fragment on Query {
allThreads (first:300) {
edges {
node {
// child's fragment included here
}
},
}
}
`,
},
Webpack checks this against my live schema and likes it. Then I create the following in my index.js for router:
const ViewerQueries = {
store: () => Relay.QL`query { allThreads(first:300) }`
};
ReactDOM.render(
<Router
forceFetch
environment={Relay.Store}
render={applyRouterMiddleware(useRelay)}
history={browserHistory}
>
<Route path='/' component={ThreadList} queries={ViewerQueries} />
</Router>
, document.getElementById('container')
)
Already I'm feeling a little unsure because I figure I'm doing ViewerQueries wrong, but it's hard to know because everyone else uses this to accommodate their viewer wrapper on their GraphQL connections, but Graphene has a different wrapper on each connection, so this might only work for my single route, but that's okay for now. Webpack likes it against the schema again. But when I load the page, I get a 'bad request' and the error that:
"Fragment F1 cannot be spread here as objects of type
ThreadNodeConnection can never be of type Query"
To be honest, that's about where I couldn't proceed, because I'm clearly not understanding something about either how Graphene Django constructs the schema, or how the GraphQL fragments should be written, or how the Route query should be written. Trouble is I can't figure out which of these things is wrong, and there don't seem to be any resources out there around people using these particular combinations of technologies.
For completeness, my Graphene Django schema setup is (slightly simplified):
project/threads/schema.py:
class ThreadNode(DjangoObjectType):
class Meta:
model = Thread
interfaces = (relay.Node, )
...
class Query(graphene.AbstractType):
all_threads = DjangoFilterConnectionField(ThreadNode)
thread = relay.Node.Field(ThreadNode, id=graphene.Int())
def resolve_all_threads(self, args, context, info):
return Thread.objects.select_related('author__profile').all()
def resolve_thread(self, args, context, info):
id = args.get('id')
if id is not None:
return Thread.objects.get(pk=id)
return None
project/schema.py:
class Query(project.threads.schema.Query, graphene.ObjectType):
pass
schema = graphene.Schema(query=Query)
If anyone has used this particular combination before and has any advice, that'd be amazing.
I had this same issue and after a long search i finally found this answer
https://github.com/facebook/relay/issues/1558#issuecomment-297010663
Since relay 1 don't support connections as root query. you should ad a viewer as a node interface to wrap your query.
So in your server main query (project/schema.py) you should add the following code:
class Query(project.threads.schema.Query, graphene.ObjectType):
viewer = graphene.Field(lambda: Query)
id = graphene.ID(required=True)
def resolve_viewer(self, args, context, info):
return info.parent_type
def resolve_id(self, args, context, info):
return 1
class Meta:
interfaces = (graphene.relay.Node,)
Now in you graphiql you can format your query like this:
query {
viewer{
allThreads(first:10) {
edges {
node {
id
}
}
}
}
}
In client side you can create your container like this:
export default Relay.createContainer(ThreadList, {
fragments: {
viewer: () => Relay.QL`
fragment on Query {
id
allThreads(first:10){
edges{
node{
id
}
}
}
}
`,
},
});
I hope this can help you

Ionic2: invalid page component: ProjectInfoPage

export class ProjectDetail {
page: string;
}
the page info contained in json, like this:
{
"data":[
{
page: "PageInfoPage"
},
{
page: "PageInfoPage1"
}
]
}
I parse info from this json,then saved in Array.
when execute this.nav.push(pd.page),throw exception as title described.I don't know how to convert 'string' to 'component'.
============================================================
I use the method like Angular 2 - Resolve Component Factory with a string described. This is my code:
itemClick(pd: ProjectDetail) {
var factories = Array.from(this.resolver['_factories'].keys());
var factoryClass = <Type<any>>factories.find((x: any) => x.name === pd.page);
const factory = this.resolver.resolveComponentFactory(factoryClass);
const compRef = this.vcRef.createComponent(factory);
if (this.componentRef) {
this.componentRef.destroy();
}
this.componentRef = compRef;
this.nav.push(compRef, {
item: pd,
pid: this.project.pid
});
}
it still does not work.Thank you for your answer.
At last,I solved it with a stupid method.As I create a map like this:
componentRegistry = {
'ProjectInfoPage': ProjectInfoPage
};
And then push like this:
this.nav.push(this.componentRegistry[pd.page], {
item: pd,
pid: this.project.pid
});
Normally, you have to import the actual component class for the page that you want to navigate to and then push that class onto the stack. By default, there is no way built into ionic2 to navigate via string references. I had the same problem today where I wanted to be able to navigate using strings rather than pushing the component class on the stack.
Check out the following link from the ionic forums on how to accomplish this. Look at the last two responses to the thread, which include how to solve this problem from beta stages and then an updated answer for how to do so with ionic 2.2.0. Although I'm pretty sure the same solution will work for all versions of ionic 2 since final release.
https://forum.ionicframework.com/t/ionic2-navigation-circular-depencies/41123/5

How to override update (put) method in loopback js

Based on loopback documentations, We can override remote methods.I want to override PUT : /products/{id} requests.
I try this:
module.exports = function (product) {
product.save = function(data,callback){
callback();
}
};
I try it with : update , updateAttributes , upsert and all related methods but still not working...
Although overriding create method working but update no!
Is there any suggestion?
Use product.prototype can trigger put requests like this :
product.prototype.updateAttributes = function (data,callback) {
console.log('updateAttributes');
callback();
};
If you want to disable the API end point, you can use the following,
Product.disableRemoteMethod('update', true)
Product.disableRemoteMethod('updateAttributes', true)
Product.disableRemoteMethod('upsert', true)
Documentation Link - https://docs.strongloop.com/display/public/LB/Exposing+models+over+REST#ExposingmodelsoverREST-Exposingandhidingmodels,methods,andendpoints

Loopback include unrelated lists

In Loopback it is easy to include relational objects when querying for data. For example, one can include all the comments that belong to a blog post in a single call using the include filter.
But in my case I want to get data that doesn't have a relation.
I have a User Detail page. On that page a user can choose a username and there's also a dropdown list where a user can choose from what country he is.
So from the client side I do something like:
Country.find().$promise.then(function(countryData) {
$scope.countries = countryData;
});
Player.find().$promise.then(function(playerData) {
$scope.player = playerData;
}
But what if I get more lists that I want to fill? Like, city, state, colors etc.
Then I'd have to make a lot of separate calls.
Is there a way to include all this data in one call, eventhough they have no relation? Something like this:
Player.find({ filter: { include: ["countries", "colors"] } }).$promise.then(function(data) {
// some stuff
}
You may want to try using the Where filter as documented here
An example of this for querying two specific things would be:
Post.find({where: {and: [{title: 'My Post'}, {content: 'Hello'}]}},
function (err, posts) {
...
});
You could create a remote method on one of your models that makes the calls internally and packages them back up for you.
Use some promise library if not using ES6 to wait for all and then return
Model.getAll = function(next) {
var promises = [];
promises.push(Model.app.models.Country.find());
promises.push(Model.app.models.Player.find());
promises.push(Model.app.models.Color.find());
Promise.all(promises)
.then(function(results) {
next(results);
});
}
/**
Register your remote method here
*/
You could create a remote method on one of your models that makes the calls internally and packages them back up for you.
Use some promise library if not using ES6 to wait for all and then return
Model.getAll = function(next) {
var promises = [];
promises.push(Model.app.models.Country.find());
promises.push(Model.app.models.Player.find());
promises.push(Model.app.models.Color.find());
Promise.all(promises)
.then(function(results) {
next(results);
});
}
/**
Register your remote method here
*/
I have problem and try with this solution but i get error "Failed with multiple errors, see details for more information.". It seems like there is bug on Loopback while using promise.all

Ember makes unwanted call to backend in model hook

I want to be able to retrieve a certain conversation when its id is entered in the URL. If the conversation does not exist, I want to display an alert message with a record not found.
here is my model hook :
model: function(params){
return this.store.filter('conversation', { status : params.status}, function(rec){
if(params.status == 'all'){
return ((rec.get('status') === 'opened' || rec.get('status') === 'closed'));
}
else{
return (rec.get('status') === params.status); <--- Problem is here
}
});
}
For example, if I want to access a certain conversation directly, I could do :
dev.rails.local:3000/conversations/email.l#email.com#/convid
The problem is when I enter a conversation id which doesn't exist (like asdfasdf), ember makes call to an inexisting backend route.
It makes a call to GET conversation/asdfasdf. I'm about sure that it is only due to the record not existing. I have nested resources in my router so I'm also about sure that it tries to retrieve the conversation with a non existing id.
Basically, I want to verify the existence of the conversation before returning something from my hook. Keep in mind that my model hook is pretty much set and won't change, except for adding a validation on the existence of the conversation with the id in the url. The reason behind this is that the project is almost complete and everything is based on this hook.
Here is my router (some people are going to tell me you can't use nested resources, but I'm doing it and it is gonna stay like that so I have to work with it because I'm working on a project and I have to integrate ember in this section only and I have to use this setup) :
App.Router.map(function(){
// Routing list to raw namespace path
this.resource('conversations', { path : '/' }, function() {
this.resource('conversation', { path : '/:conversation_id'});
});
});
This also happens when I dont specify any id and I use the hashtag in my url like this :
dev.rails.local:3000/conversations/email.l#email.com#/ would make a call to conversation/
I know it is because of my nested resource. How can I do it?
By passing a query to filter (your { status : params.status}) you are asking Ember Data to do a server query. Try removing it.
From the docs at http://emberjs.com/api/data/classes/DS.Store.html#method_filter:
Optionally you can pass a query, which is the equivalent of calling find with that same query, to fetch additional records from the server. The results returned by the server could then appear in the filter if they match the filter function.
So, remove the query:
model: function(params){
return this.store.filter('conversation', function(rec) {
if (params.status == 'all') {
return rec.get('status') === 'opened' || rec.get('status') === 'closed';
} else {
return rec.get('status') === params.status;
}
});
}
Ok so here is what I did. I removed my nested resource because I realised I wasn't using it for any good reason other than redirecting my url. I decided to manually redirect my url using javascript window.location.
This removed the unwanted call (which was caused by the nested resource).
Thanks to torazaburo, you opened my eyes on many things.