Is there a way in Ember to configure a custom REST url for a specific Model?
Like with this model:
App.Post = DS.Model.extend({
title: DS.attr('string'),
comments: DS.hasMany('App.Comment')
});
App.Comment = DS.Model.extend({
content: DS.attr('string'),
post: DS.belongsTo('App.Post')
});
And this Store:
app.Store = DS.Store.extend({
revision : 11,
adapter : DS.RESTAdapter.extend({
namespace : 'rest'
})
});
I want that the comments are retrieved via /rest/post/{id}/comments instead of /rest/comments which is the default behaviour.
Is it possible to configure a rest-url for one specific Model?
You can register an additional adapter and 'scope' it to your model.
App.Store.registerAdapter('App.Post', DS.RESTAdapter.extend({
url: "/rest/post/"
}));
Is this for literally just for one model across your entire app or is this the default "hasMany" uri that your REST backend uses? I ask because my api (django rest framework) uses this exact uri and it required a full blown pull request on the ember-data project because to build the URL the adapter needs the related "parent" or "owner" (something rails devs never needed so it didn't exist).
I would write your own adapter (just subclass the base adapter so you only override the single hasMany that is different). The method I wrote for my adapter is below and here is my full blown adapter for reference.
This is ember-data revision 11 friendly btw (have not upgraded to 12 yet)
https://github.com/toranb/ember-data-django-rest-adapter/blob/master/tests/adapter.js
findMany: function(store, type, ids, parent) {
var json = {}
, root = this.rootForType(type)
, plural = this.pluralize(root)
, ids = this.serializeIds(ids)
, url = this.buildFindManyUrlWithParent(store, type, ids, parent);
this.ajax(url, "GET", {
success: function(pre_json) {
json[plural] = pre_json;
Ember.run(this, function(){
this.didFindMany(store, type, json);
});
}
});
},
Related
Beforehand, hello to everyone!
I initialize Graphql in Loopback 4 like this:
const graphqlPath = '/graphql';
// #ts-ignore
const oas: Oas3 = await (<Oas3>app.restServer.getApiSpec());
console.log(graphqlHTTP);
const {schema} = await createGraphQLSchema(oas, {
strict: false,
viewer: true,
baseUrl: url,
});
//#ts-ignore
const handler: graphqlHTTP.Middleware = graphqlHTTP({
schema,
graphiql: true,
});
app.mountExpressRouter(graphqlPath, handler);
console.log(`Graphql: ${url}${graphqlPath}`);
Then I have a relation Favors>User (a User can have many Favors, but a Favor has only one User). I've created this relation with lb4 relation, and I haven't made any other change.
User Model:
#hasMany(() => Favor)
favors: Favor[];
Favor Model:
#belongsTo(() => User)
userId: string;
At the moment of the query (http://localhost:3000/graphql) this is what happens:
{
favors {
id
userId
user {
id
}
}
}
I have no idea if it has something to do with the loopback-connector-mongodb which does not match ObjectId correctly, but I have no clue how to solve this.
My package.json:
"#loopback/core": "^2.12.0",
"openapi-to-graphql": "^2.2.5",
"loopback-connector-mongodb": "^5.4.0",
Hello from the LoopBack team 👋
In order to allow openapi-to-graphql understand relations, the OpenAPI schema produced by a LoopBack application must describe Links between entities.
LoopBack 4 does not provide such metadata out of the box. We have been discussing this use case in GitHub issue loopback-next#2153, unfortunately we haven't found a clear solution yet.
What you can try: In your controllers, enhance your response specifications with a links section pointing to relevant API endpoints for accessing the related models.
Is it possible/feasible to use KeystoneJS along with a front-end developed in Flutter for web? Would it make sense to do so? Any hint would be appreciated.
Keystonejs is any other backend which provides headless cms capability. You can use this like any other backend using GraphQL client if available in Flutter.
I see Flutter does support http request you can use this feature to call GraphQL using plain http query (http package). example query to get all users from User list
var client = http.Client();
try {
var response = await client.post('https://keystoneproject.com/admin/api',
body: { 'query': 'query { allUsers { id name email isAdmin }}' });
// this gives you result in JSON format `{ data: { allusers { id: "id value", name: "name of user", email: "email of user", isAdmin: false } }
print(await client.get(response.bodyFields['data']));
} finally {
client.close();
}
body should also contain variable field if your query has any parameter (see GraphQL reference on how that work, I don't think that is scope of the answer)
Currently i am working on a single-page-application with backbone.js.
My server is providing a REST api.
http://server.com/article is returning the latest articles from all categories.
http://server.com/article/categoryname is returning the latest articles from specified category only.
My current collection looks like this:
define(['backbone', 'models/article'], function(Backbone, Article) {
return Backbone.Collection.extend({
model: Article,
url: "http://server.com/article",
});
});
So with fetch i can receive all the latest articles from all categories. Where should i implement my specific category requests, so i do not have to create a collection for every category by myself and a possible caching won't be so difficult at all.
Would it be better to change my rest api and receive all articles and filter them in the backbone app? Or should i implement a fetchFromCategory method in my collection and build the caching myself?
I am thankful for every hint or idea!
If fetching all the Articles in a single request is not an issue, you can do that. To get articles by categoryName, you can then add a method in the collection as below :
define(['backbone', 'models/article'], function(Backbone, Article) {
return Backbone.Collection.extend({
model: Article,
url: "http://server.com/article",
getArticlesByCategory : function(category) {
return this.filter(function(article){
//Assuming 'Article' has a property named 'categoryName'
return article.get('categoryName') == category;
});
}
});
});
Now, if articles is your collection you can do :
var categoryXYZArticles = articles.getArticlesByCategory('XYZ');
When we create our apps, we usually add our own routes.
So using the baucis.rest i added some custom routes like example:
var controller = baucis.rest( {
singular: 'User'
} );
controller.put('/myroute/:id', function(req,res,done){
//doing something
})
My app runs and using the swagger ui i can see the operations about users.
GET /Users/{id} description
PUT /Users/{id} description
......
I would like to add my "/myroute/:id' to the generated swagger api.
PUT /Users/myroute/{id} description
Does anyone know how to do about this?
As of v0.9.0 , you can modify the swagger definitions directly. It's purely cosmetic, only altering the swagger documentation, not any other functionality.
For example:
var controller = baucis.rest('User');
controller.swagger.apis.push({
'path': '/Users/myroute/{id}',
'description': 'Myroute custom description.',
'operations': [
{
'httpMethod': 'PUT',
'nickname': 'putSomethingCustom',
'responseClass': 'User',
'summary': 'Something custom.'
}
]
})
controller.swagger.models is also exposed.
I've started experimenting with Backbone.js, and was struck by the documentation for the documentation for the url property on Backbone.Model.
In particular, I'm building out a REST API that uses HATEOAS/hypermedia to drive the client(s).
I can see the usefulness of Backbone's default behaviour of building up URLs itself for items in a collection, but for my case, would prefer to have the model URLs built out of the data that is parsed.
Has anyone extended/built on Backbone to make it do this? Maybe building upon a "standard" like HAL?
EDIT:
For clarification, let's say I have the following:
GET /orders >>
[
{
"_links": {
"self": "/orders/123"
}
"name": "Order #123",
"date": "2012/02/23"
},
{
"_links": {
"self": "/orders/6666"
}
"name": "Order #666",
"date": "2012/03/01"
},
]
and I have an Order model like:
var Order = Backbone.Model.extend({
});
I would like the url property to be automatically pulled out of the "self" reference in the HAL. I think creating a new base model something like (not tested):
var HalModel = Backbone.Model.extend({
url: function() {
return get("_links").self;
},
});
Thoughts?
I've extended backbone to do exactly this, the library is available here:
https://github.com/mikekelly/backbone.hal
Thanks for the clarification #Pete.
I think I see what your proposing and I suppose it could work. However, in your example, you first had to know the /Orders url before you were able to get the orders. And if you reworked your json to have an id property, you'd be pretty close to the default implementation of backbone.
Now if you just want to use a generic model or base model (e.g. HALModel) and just bootstrap it with data, your approach could be useful and definitely could work. However, I would look at overriding parse to pull the url out and set it on the model:
parse: function(response) {
this.url = response._links.self;
delete response._links;
return response;
}
I complement here the response of Simon to explain how to easily do it using gomoob/backbone.hateoas.
// Instanciation of an Hal.Model object is done the same way as you're
// used to with a standard Backbone model
var user = new Hal.Model({
firstName: "John",
lastName: "Doe",
_links: {
avatar: {
href: "http://localhost/api/users/1/avatar.png"
},
self: {
href: "http://localhost/api/users/1"
}
},
_embedded: {
address: {
"city" : "Paris",
"country" : "France",
"street" : "142 Rue de Rivoli",
"zip" : "75001",
"_links" : {
"self" : {
"href" : "http://localhost/api/addresses/1"
}
}
}
}
});
// Now we you can easily get links, those lines are equivalent
var link1 = user.getLink('avatar');
var link2 = user.getLinks().get('avatar');
// So getting self link is simple too
var self = user.getLink('self');
// All the Hal.Link objects returned by backbone.hateoas are in fact
// standard Backbone models so its standard Backbone
link1.get('href');
link1.getHref();
// You can do more with shortcut methods if your HAL links
// have more properties
link1.get('deprecation');
link1.getDeprecation();
link1.get('name');
link1.getName();
link1.get('hreflang');
link1.getHreflang();
link1.get('profile');
link1.getProfile();
link1.get('title');
link1.getTitle();
link1.get('type');
link1.getType();
linke1.get('templated');
link1.isTemplated();
// You can also manipulate embedded resources if you need
user.getEmbedded('address').get('city');
user.getEmbedded('address').getLink('self');
...
Finally we provide an Hal.Model.url() implementation which is more powerful than standard Backbone url() and which is very useful if you use HAL.
// By default url() returns the href of the self link if this self
// link is present
user.url();
// If the self link is not defined then url() has the same behavior
// as standard Backbone url() method
// My user is link to a user collection having a URL equal to
// 'http://localhost/user1'
user.url(); // http://localhost/users/1
// My user is not link to a user collection in this case the URL is
// generate using the model urlRoot property by default
user.urlRoot = 'http://myserver/users';
user.url(); // http://localhost/users/1
// backbone.hateoas also allows you to define an application wide root
// URL which prevent to use absolute URLs everywhere in your code
Hal.urlRoot = 'http://localhost/api'; // HAL root API URL
var user = new Hal.Model({ id : 1});
user.urlMiddle = 'users';
user.url(); // http://localhost/api/users/1
Hope this helps, don't hesitate to post issues on our github if you need help on this.
You can override the url function on the model to calculate the URL however you want; it's completely extensible.