How do I perform specific parentless requests using Restangular in a neat way? - angularjs

Say I have an API endpoint at /users and another one at /cars. Naturally, a GET request to either of them will get all users or cars available. Now, a GET /users/74/cars should return all cars belonging to user 74.
But my app has many models related to cars, not just users, so more endpoints exist like /shops/34/cars and /mechanics/12/cars. For simplicity, I want all PUT/PATCH requests to be made to the main /cars endpoint.
At the moment of performing the save, Restangular will by default do a PUT request to the endpoint through which the item was loaded. But that endpoint do not exist.
It also provides a nice Restangular.setParentless(['cars']) method that will discard the first part of the url. However, I don't want to do this globally, but specifically for a particular element.
The neatest would actually do it globally, but restrict it for a specific method, like: Restangular.setParentless(['cars'], ['PUT']).
Anything like that around? Or am I overcomplicating it?
So far I tried stuff I don't like:
delete car.parentResource;

I would recommend using self reference links. A self reference link is a link which stores the route which should be used for GET/PUT/DELETE etc. on the item, rather than the URL from which it was pulled.
Example, update the mileage on one of user id 74's cars:
First, configure Restangular to look for a self link property called 'self' on each object.
RestangularProvider.setRestangularFields({
selfLink: 'self'
});
Next, make your call to get the cars. I'll assume that you have already modified your API to return a property called 'self' on each object that has the URL to it's proper API endpoint.
GET /users/74/cars
[
{
"id": 12,
"model": "Camaro",
"make": "Chevrolet",
"year": 1969,
"color": "red",
"odometer": 67294,
"license": "ABC12345",
"self": "/cars/12"
},
{
"id": 14,
"model": "Gallardo",
"make": "Lamborghini",
"year": 2015,
"color": "black",
"odometer": 521,
"license": "XYZ34567",
"self": "/cars/14"
}
]
We want to add some miles to one of them, and then save it. The entire Restangular code would look like:
Restangular.one('users', 74).all('cars').getList().then(function(cars){
cars[1].odometer = 613;
cars[1].put();
});
The PUT will go to /cars/14 instead of /users/74/cars/14. This is very useful for applications like yours that relate models as a graph rather than a strict hierarchical tree.

Related

How do I call a multiple layer deep Object or a Value of a JSON database?

I created a Json Server Database like this:
"Time":
[
{
"id":1,
"name":
[
{
"id":1,
"checkin":
[
{
"id":1,
"date":"123",
"time":"123"
},
{
"id":2,
"date":"123",
"time":"123"
}
]
},
{
"id":2,
"checkout":
[
{
"id":1,
"date":"123",
"time":"123"
}
]
}
]
}
]
I don't want to get the entire Database and go through it. I just want to tell the Database where exactly my Object is and have it returned.
How would I call the call for example the first Check-in Object?
I use the Angular HttpClient like this:
this.http.get(endpoint, JSON.stringify(time), this.httpOptions))
So I need the Exact Endpoint in a format like: endpoint/id/id or similar
I imagined it like this: endpoint/time/1/1
With output:
[
{
"id":1,
"date":"123",
"time":"123"
}
]
If this is not possible please tell me anyways.
PS: The question from this thread is essentially the same as mine. Also the JSON documentation doesn't real help either, it just says you need custom routes for multilayer JSON strings but not how to implement these routes.
I'm not sure if I understand correctly where you are returning the data from. If you meant json-server, just look at the documentation (here) and then you could use an endpoint like "/posts?Id=2"
However, if you mean your own API, which does not have an endpoint that returns one record, e.g. by its ID, the only convenient solution is to create a service that will map the result from the server and return the desired value.
You can do all this in one place, but for clearer code, I recommend dividing it into:
service that will download data from the server
service that will map the data on the basis of a given parameter
component that will display the data
Below is a working example on Stackblitz.
example
Note that in the app-component I pass the ID 32 to the method from the mapping service as the parameter. The mapping service then calls a method that sends the request for all the data.
The important thing is that all data is returned to the application, not just one record. If the API you are using does not provide such an endpoint, it is not possible to return only one record.
Apparently a request like I wanted to call is still not possible. The only way to come close is to fake it with custom Routes and flattening the JSON structure like in this old thread.

Open URL in IBM Watson conversation

I am using a Blumix free account to develop a chat-bot using watson conversation.
How do I add a clickable URL in the response, or automatically call a URL in browser?
I have edited the "advanced response" using the suggestions as described on this page but could not get it work.
How can I achieve that?
I don't know if I understood your question correctly, but.. if you wants add some url inside flows Conversation Service (IBM Watson), try it:
1º: Add the url with tag <a target> and href= your URL inside flows. See the example:
JSON:
"output": {
"text": "This is a link <a target=\"_blank\" href= \"https://www.choosemyplate.gov\">Food and nutrition Guide</a>.\n<br/><br/>Talk to you later, bye for now!"
},
2º See that it did not work inside the Conversation, because it will be your browser that will render the html.
3º If you open with your browser, it works, see:
See that the link is showing up, and this will work for other things in html, like button, for example...
But if you can: based on user input should access a url:
This is done by using two features: Context.request skip_user_input
A request is a special context variable that has args, name and result. It is used to tell the calling app that it should do some action based on this variable.
Setting skip_user_input is optional. In many cases, you might want to execute some business logic in your application and then provide its results via result. Setting skip_user_input to true, will tell Watson Conversation to not wait for input from the user. Thus, your condition on the next node should be based on the content inside result.
{
"output": {},
"context": {
"request": {
"args": {
"url_to_invoke": "your_url"
},
"name": "Call_A_URL",
"result": "context.response"
},
"skip_user_input": true
}
}
Reference: IBM Professional #Dudi: here.

Is including additional information in the output object a good idea?

I'm experimenting with a Conversation where I would like to modify the output in a couple of different ways:
different output for speech or text
different output depending on the tone of the conversation
It looks like I can add extra output details which make it through to the client ok. For example, adding speech alongside text...
{
"output": {
"speech": {
"Hi. Please see my website for details."
},
"link": "http://www.example.com",
"text": {
"Hi. Please see http://www.example.com for details."
}
}
}
For the tone, I wondered about making up a custom selection policy, unfortunately it seems to treat it the same as a random selection policy. For example...
{
"output": {
"text": {
"values": [
"Hello. Please see http://www.example.com for more details.",
"Hi. Please see http://www.example.com for details."
]
},
"append": false,
"selection_policy": "tone"
}
}
I could just add a separate tone-sensitive object to output though so that's not a big problem.
Would there be any issues adding things to output in this way?
You can definitely use the output field to specify custom variables you want your client app to see with the benefit that these variables will not persist across multiple dialog rounds (which they would if you would add them to the context field).
Now currently there is no "easy" way how to define your custom selection policy (apart from the random and sequential supported by the runtime right now) - but you could still return an array of possible answers to the client app with some attribute telling the client app which selection policy to use and you would implement this policy in the client app.

Include roles in User.login() and User.getCurrent() Angular SDK

I'm currently writing an administrative interface using the Loopback Angular SDK. After having dug through the documentation and code, I'm still no wiser as to how to include the user's roles in the response. It's causing me real headaches on the frontend because I'm not yet experienced enough with Angular to figure out how to enforce a role check on each of my states (I'm using UI-Router).
client: /auth.js
// Log the user in
$scope.doAuth = function() {
$scope.hasError = false;
$scope.busy = true;
$scope.loginResult = User.login({include: 'roles'}, $scope.credentials,
function wasSuccessfulAuth(authResponse) {
$scope.busy = true;
$rootScope.isAuthenticated = true;
$rootScope.user = authResponse.user;
$location.path('dashboard');
},
function wasFailedAuth(authResponse) {
$timeout(function() {
$scope.hasError = true;
$scope.authError = authResponse.data.error.message || 'Unknown error';
$scope.busy = false;
}, 1000);
}
)
}
server: /common/models/user.json
{
"name": "user",
"plural": "Users",
"base": "User",
"properties": {
},
"relations": {
"roles": {
"type": "belongsTo",
"model": "RoleMapping",
"foreignKey": "principalId"
}
},
"acls": [],
"methods": []
}
So this works in the API explorer, I have the routes I'd expect with an object that has a relation, but I can't seem to get any further than that... All that gets returned is the standard user login stuff (id, accessToken, email, etc) The docs seem to run cold when I get this far but I'd have thought this would have been a common use case?
This is a bit of a showstopper for me.
It's actually surprisingly easy to solve this problem using LoopBack: this is where "model scopes" come in very handy -- including the default scope which I find extremely useful for this type of situation.
First, a brief explanation of model scopes:
A model scope is like a saved query or "view", that allows you to specify a built-in filter for any query for that scope. For example, if you set the default scope to a valid filter, every single query (of any kind) against your model will have this filter applied!
This can get you in a heap of trouble, but there's one use-case that's pretty safe (all other things equal) and actually addresses your question perfectly: when I said a scope lets you give a valid filter, it turns out filters aren't just where clauses, but also include, limit, etc.
So to solve your problem, you simply need a default scope on your User model that includes whatever you need to include. For your example:
Simply add a scope object to your common/models/user.json:
{
"name": "user",
"plural": "Users",
"base": "User",
"scope": {
"include": [
"roles"
]
},
"properties": {
},
"relations": {
"roles": {
"type": "belongsTo",
"model": "RoleMapping",
"foreignKey": "principalId"
}
},
"acls": [],
"methods": []
}
By adding a default scope with an "include", LoopBack will automatically embed the object(s) of the related model based on the named relation (just like if you added it in your query -- which as discussed, is not possible, or at least not easy, in this case).
One caveat: since Role and RoleMapping are built-in models and are surely marked as non-public, I am not actually sure whether you can include them directly (but for a different reason than above). I haven't worked enough with ACLs (yet), but presumably there's more complexity around access controls especially in related models.
So, whereas my example code above explain the mechanics of doing the include here, the policy concern may slow you down (I'd be curious to know if they do).
That said, however, I guess you could add a derived model (from RoleMapping) that you make public (just like you did for user), and use it instead everywhere (including in the relation to/from user) -- hopefully that's clear (let me know if not).
In conclusion: If you add a default scope to your derived user model, to do the include for you, the AngularJS service wrapper (built by lb-ng) will be none the wiser (the include all happens on the backend):
$scope.loginResult = User.login($scope.credentials,
function wasSuccessfulAuth(authResponse) {
console.log('Related models are here: ', authResponse.roles,
authResponse.user);
...
In other words, the resulting model will contain an array, .roles[], containing the related roles to this user (based on your relation definition), and .user with the entire user model right there!
This latter point is unclear but I'm confident in that, because I did exactly the above but with a different related model that I know works. And to my surprise, user was included as well, since that's explicitly requested by the LoopBack $resource wrapper (the one created by lb-ng). So, in fact, you don't have do a separate query to get the user -- it's already there! There's no API that I see when using the $service wrapper, to get at that built-in include and change it; I guess that's what was posted in a comment above.
Hope this is helpful.
Steve
User.login returns AccessToken instance. To get user role, you should make separate request to fetch user, including role.

Explanation of Ext.direct API

I'm trying to get a grip on Ext.direct. On the official page there is this description of the API:
The purpose of the API component of the Ext Direct stack is to output the method configurations for Ext Direct to create client-side stubs. By generating these proxy methods, we can seamlessly call server-side methods as if they were client-side methods without worrying about the interactions between the client and server-side.
I just don't quite get what it means by ...to output the method configurations for Ext Direct to create client-side stubs. Would someone care to explain what this means at a grassroots level?
This will make more sense if you look at the output from the api.php resource included in the following example.
Note that this is being loaded on the page as a <script/> tag, ie:
<script type="text/javascript" src="php/api.php"></script>
When you open the src link you'll see the following JavaScript being generated by server-side PHP (see block of javascript code below).
In other words, PHP is doing the bit where it ... output(s) the method configurations for Ext Direct to create client-side (ie JavaScript) stubs.
Now the next question you should be asking if you want to make sense of this is: Why bother generating client side JavaScript using server side PHP (or other language of choice)?.
Ext.ns("Ext.app");
Ext.app.REMOTING_API={
"url": "php\/router.php",
"type": "remoting",
"actions": {
"TestAction": [{
"name": "doEcho",
"len": 1
}, {
"name": "multiply",
"len": 1
}, {
"name": "getTree",
"len": 1
}, {
"name": "getGrid",
"len": 1
}, {
"name": "showDetails",
"params": [
"firstName",
"lastName",
"age"
]
}],
"Profile": [{
"name": "getBasicInfo",
"len": 2
}, {
"name": "getPhoneInfo",
"len": 1
}, {
"name": "getLocationInfo",
"len": 1
}, {
"name": "updateBasicInfo",
"len": 0,
"formHandler": true
}]
}
};
This seems to be mimicking the way a WSDL works in that it can provide a service description and list all the options available for quering. In other words: Ext.Direct API is taking a concept from SOAP and applying it to a Javascript setting.
The back-end contains the API so this is the easiest place to generate a service definition with all the method names and signatures. Once the Ext.Direct API method stubs are provided (in the back-end), the front-end Ext.Direct library will do the plumbing and turn these into actual functionality that can be queried and used in JavaScript. Much in the same way as SOAP proxy classes can be automatically generated (in PHP/C# or Java) using the WSDL.
Personally I think this is a bit too airy-fairy for my liking. Most APIs are pretty straight forward and trying to implement something akin to WSDL actually makes consumption a lot harder than it would be if you just talk to it directly.

Resources