How to handle model / API response translation in AngularJS? - javascript

I have an angular application that requests data from a JSON API. A sample API response might be:
{
id: 1,
name: 'JJ',
houseId: 2
}
In my angular application I will have models representing a User, which also has a reference to a House object:
{
id: 1,
firstName: 'JJ',
surname: '',
house: {
id: 2,
address: 'XXX'
}
}
The application model and API responses differ in that there is one field for the name in the API response, but two in my application model. Is there an 'angular' way I can do some transformation from an API call response object to my application model to ensure that I am always dealing with consistent objects in my controllers/services?
Related to this, the API responds with the database id of the house object associated with that user, and not with the full house object included in the JSON. Is there a way to set my object up to automatically resolve this when needed?
As an example, I would like to display this user, with his address. If the object was fully resolved I could use 'user.house.address'. However, using the plain JSON response object, this would be undefined. Instead of having to explicitly resolve the house object by using the house API with the houseId, I would like this to happen 'behind the scenes' by previously stating how such an id would be resolved if the object is accessed.
Or am I approaching this the wrong way and the API response should be used to dictate the data structure of my application and explicit lookups via object id's is the preferred way?

Related

Should I interpolate and use local data model or use server response directly?

I am developing an application having angular2 at front-end and laravel at back-end. The front-end communicates with the server using RESTful APIs.
The front-end has a page where an angular component fetches the data from the server and displays it on the screen. Let's assume we have following JSON response
{
"books": [1, 2, 3],
"is_active": true,
"user": {
"first_name": "Munish",
"last_name": "Kumar",
"age": 25
}
}
Now, should I interpolate the object properties into HTML directly from server response like so {{ responseObj.user.first_name }} ?
OR
Should I first transform the server response in an angular 2 model class?
export class User {
firstName: string;
lastName: string;
age: number
constructor(fname, lname, age) {
this.firstName = fname;
this.lastName = lname;
this.age = age;
}
}
const u = responseObj.user;
let user = new User(u.first_name, u.last_name, u.age);
and then in HTML {{ user.firstName }}
If I don't model the server response in angular class then It might be tedious to change the object properties wherever these properties are being used, if server incorporates a change in JSON response during development.
and sometimes it seems unnecessary to model the response before just displaying it on a page.
is there any best practice or general rule to apply?
It's always better to create a model for your response as an interface. Implement that interface on your custom object as a type.
Assign the response from your subscribers next function to your custom object, and then interpolate the custom object on your component template.
This way you are ensuring that the response always adheres to your object model.

Combine objects into new object as json for post for web api request

I am using Angular 4 with Typescript and ASP Core with C#. I am trying to combine objects together before calling a post to my web api. Currently I have two objects with values that I want to post as one object.
Let say I have two interfaces
export interface Student {
name: string;
}
export interface Teacher {
name: string;
}
And I wanted my json in my body of the post to look like this as my ASP Core is expecting this as a parameter to the web api request.
{
"StudentName": "John Doe",
"TeacherName": "Jane Doe"
}
I am using the following to create the json for the body but this puts it into two separate records in the json. This also does not allow me to select specific properties if my interfaces had more than what the request required.
const body = JSON.stringify({ student, teacher });
Next I tried to access only the specific member variables in the JSON.stringify method, but for some reason it does not work. In addition, if this even worked it would end up with two properties with the same name.
const body = JSON.stringify({ student.name, teacher.name });
I am not sure if this is a typescript, javascript or angular issue. I tried searching online for some help but I don't think I am using the right keywords.
Thanks in advance!
The problem is that you're not labeling your object items:
const body = JSON.stringify({ StudentName: student.name, TeacherName: teacher.name })
is the expected format.

Check an API call for differences

I make an API call and pull down JSON data and store in an Array.
Whats the best way to periodically check if there is a change in the Array that's pulled down and return an Array of the new data?
JSON from API call:
{
success: true,
message: "",
result: [{
Currency: "GBP",
IsActive: true,
BaseAddress: "1N52wHoVR79PMDishab2XmRHsbekCdGquK",
Notice: null
},
{
Currency: "USD",
IsActive: true,
BaseAddress: "LhyLNfBkoKshT7R8Pce6vkB9T2cP2o84hx",
Notice: null
},
{
Currency: "YEN",
IsActive: true,
BaseAddress: "D9GqmkGCpgtnXP7xMD78v9xfqeDkqBZBMT",
Notice: null
}
]
};
Store in an array:
const currencies = [...new Set(data.result.map(a => a.Currency))];
console.log(currencies);
Now say the website add CHF how would I poll the API and get an Array just containing the new data?
Specifically whats the best way to schedule another API call, using setTimeout or is there a better way?
Also, how do I then compare the first array with the second array and return an array containing the difference?
I guess you are making it little bit complex. Best way to achieve this purpose is web sockets.
Web sockets are used to have communication between client and server.
Lets say if you create a server in nodejs and you have a browser client. Web socket will create a communication between server and client.
If there is any changes made by server in your "ARRAY", server can send a notification that a changes has been made in the array so you can make a new request to get the updated array or server can directly send updated array to client.
Advantage of this approach is that there is not need of pull request. Server will push the data so there will be no period check between server and client. This can save a lot of time plus performance.
Please research about web sockets and implement it.

How to deal with user permissions in single page application

I'm working on a single page enterprise application with a pretty complex logic about user permissions. The huge part of it works entirely on client communicating with backend server using AJAX sending JSON back and forth. The tricky part is that I need to implement permission mechanism as on per-entity basis, and I dont know how to do it the right way.
To explain myself clearly here the example code, I have 2 entity classes on the backend User and Node:
class User {
Long id;
}
class Node {
Long id;
String name;
Status status;
Node parent;
List<User> admins;
}
enum Status {
STATUS_1, STATUS_2
}
I send JSON of parent node to the server:
{id: 1, name: "Node name 1", status: 'STATUS_1'}
And recieve JSON with a bunch of child nodes:
[
{id: 11, name: "Node name 1.1", status: 'STATUS_1'},
{id: 12, name: "Node name 1.2", status: 'STATUS_1'}
]
On the client they are displayed in a tree-like structure, like this:
Now the tricky part:
Simple user that works with application can see tree, but can't change anything.
User can change node name if he is among admins of node or any of its parent nodes.
Admins can also change status of node, from STATUS_1 to STATUS_2, but only if all child nodes has STATUS_2 status.
There is a list of super adminstrators that can do whatever they want: change properties of any node, change status as they want.
So somehow, during rendering of the tree on the client, I need to know what user can or cannot do with each of the node on the page. I can't just assign user a role within a whole application because user rights vary from one node to another. Also I can't see whole picture on the client side because child nodes may be not loaded. How can I manage user permissions in situation like this? What's the proper way or pattern to use?
Should I attach some role object to each node, or maybe a bunch of flags representing what user can or cannot do like that:
{
id: 12,
name: "Node name 1.2",
status: "STATUS_1",
canChangeName: true,
canChangeStatus: false
}
That looks pretty silly to me.
I usually solve complex (and not so complex) permission-based tasks in the application using ACL classes.
I have simple, lighweight classes, that take a model, permissions for which are being checked, and a user object into a constructor. They have a bunch of methods with names canXXXX(). These methods can optionally take some parameters also if that is needed.
If you have the same model classes on front and back, you even might be able to reuse ACLs in both cases.
Can you use this approach?

fetchRelated not fetching related

Been trying to get this up and running for a while now.
Basically i have a rest api as backend that returns json, all fine.
The problem i have is with backbone-relational. I'm sure i've just got something
wrong but i've been searching the nets for a while and couldn't find anything to help.
I'm trying to get a has many relationship between the model "Profession" and "Weapon".
Here's my code for that:
Profession = Backbone.RelationalModel.extend({
urlRoot: '../api/professions',
relations: [{
type: Backbone.HasMany,
key: 'weapons',
relatedModel: 'Weapon',
collectionType: 'Weapons',
reverseRelation: {
key: 'profession',
includeInJSON: 'id',
keySource: 'profession_id'
}
}]
});
Weapon = Backbone.RelationalModel.extend({
urlRoot: '../api/weapons'
});
Weapons = Backbone.Collection.extend({
model: Weapon,
url: function(models){
return '../api/weapons';
}
});
And a call to those api endpoints returns:
{name: "Profession1", id: 1}
[{name: "Weapon1", profession_id: 1}, {name: "Weapon2", profession_id: 1}]
So, if i understand correctly a profession.fetchRelated('weapons') should send an httprequest to the url for the weapons collection and pull the object which have a profession_id of 1. But nothing happens when i run profession.fetchRelated('weapons')
So, if i understand correctly a profession.fetchRelated('weapons') should send an httprequest to the url for the weapons collection and pull the object which have a profession_id of 1. But nothing happens when i run profession.fetchRelated('weapons')
This is not how I understand Backbone-relational to work - with the caveat that I'm working with an older version, and have not yet investigated the latest versions.
From my understanding, Backbone-relational wants data that looks different from your API responses.
I think that Backbone-relational wants references to nested models in the parent model response, either fully nested:
{
name: "Profession1",
id: 1,
weapons: [
{name: "Weapon1", profession_id: 1},
{name: "Weapon2", profession_id: 1}
]
}
In which case, it will fully populate the nested models.
Or, as references:
{
name: "Profession1",
id: 1,
weapons: ['weapon1','weapon2']
}
In which case Backbone-relational will stash the related keys internally, but present an empty collection. You would then use fetchRelated to fetch the full data for the related models:
assassin.fetchRelated('weapons')
Which make a request for weapons with id 'weapon1' and 'weapon2', either as individual requests, or if your API accepts a set request, a single request, expecting a response something like:
{id: 'weapon1', name: "Weapon1", profession_id: 1}
I don't, off the top of my head, know if there's a quick, built-in way to work with your API responses, other then to write a custom function.
To add to what Edward wrote, here's how you can get fetchRelated to work. First, as Edward claimed, fetchRelated will return nothing if your API already nests the data in the JSON response. So, if in Django-Tastypie you have your resource set up to use full=True:
movies = fields.ToManyField('movie.api.MovieResource', 'user', full=True)
then something like,
myuser.fetchRelated("movies")
will return nothing because the related data will already be included in the JSON response. But where fetch related is particularly useful is when you are attempting to do some lazy loading. So, if you have full=False in your Django-Tastypie field, and your JSON response only includes the id's and resource URI to that entry, you can use fetchRelated to actually populate that data.
myuser = new User({id: 1})
myuser.fetch()
myuser.fetchRelated("movies")
And now you have access to the related movies collection. If you're also using the Tastypie-Backbone plugin, you don't need to worry about constructing a special URL return statement in the Collection. It does it all for you using the tastypie select syntax of /2;3;7

Categories