Map the backend data to Interface in Angular - json

I am new in Angular. I have issue in mapping. I called Web API in Angular following is the Json object coming from the backend:
{
"productCategoryDataModel": [
{
"productsCategortyName": "Electronics",
"productsList": [
{
"id": 1,
"productName": "Laptop",
"productDescription": "Laptop Core i7",
"productImageUrl": "fsdgdfgdfgdfgd"
},
{
"id": 5,
"productName": "IPad",
"productDescription": "IPad",
"productImageUrl": "hgfhgfhgf"
}
]
},
{
"productsCategortyName": "Grocery",
"productsList": [
{
"id": 3,
"productName": "Tomato",
"productDescription": "Tomato",
"productImageUrl": "dgdfgdfggdfgdf"
},
{
"id": 4,
"productName": "Onion",
"productDescription": "Onion",
"productImageUrl": "hgfhgfgh"
}
]
}
]
}
Following is the Response model class of Web API:
public class ProductsResponseModel
{
public List<ProductCategoryDataModel> ProductCategoryDataModel { get; set; }
}
public class ProductCategoryDataModel
{
public string? ProductsCategortyName { get; set; }
public List<ProductsList> ProductsList { get; set; }
}
public class ProductsList
{
public int Id { get; set; }
public string? ProductName { get; set; }
public string? ProductDescription { get; set; }
public string? ProductImageUrl { get; set; }
}
I have created the following interface in angular for this json:
export interface IProductsResponse {
ProductCategoryDataModel: ProductCategoryDataModel[];
}
export interface ProductCategoryDataModel
{
ProductsCategortyName: string
productsList: ProductsList[];
}
export interface ProductsList
{
ProductId: number;
ProductName: string;
ProductDescription: string;
ProductImageUrl: string;
}
Following is my Service class that calling the API:
#Injectable({
providedIn: 'root'
})
export class ProductsListService {
apiUrl: string = 'https://localhost:7025/api/ProductsManagement/GetAllProducts';
constructor(private httpClient: HttpClient) { }
getProductsGalleryData(): Observable<IProductsResponse[]> {
return this.httpClient.get<IProductsResponse[]>(this.apiUrl);
}
Following is my component ts file:
#Component({
selector: 'app-products-gallery',
templateUrl: './products-gallery.component.html',
styleUrls: ['./products-gallery.component.css']
})
export class ProductsGalleryComponent implements OnInit {
productsList: IProductsResponse[] | undefined;
constructor(private _galleryProducts: ProductsListService) { }
ngOnInit(): void {
this._galleryProducts.getProductsGalleryData().subscribe(data => {
this.productsList = data;
console.log(data);
});
}
}
The data is displayed in the Console in the form of json but i have issue in the HTML file because when i use the ngFor loop for ProductsList the properties are not coming there and it gives me error so how to map the response into the interface and how to write the html to display this data?

The keys in the data delivered by the WebAPI are camelCase, while the Angular interfaces describe PascalCase properties. Change to camelCase in the interfaces and everything should work fine.
Also, I see your product entity has an id key, while your interface describes a ProductId key. You should change that to be id.
Another approach you can take is on your backend model, you can use JsonPropertyName() [coming from System.Text.Json.Serialization] decorator, to change the name of the keys being serialized and map them to the names you have in your Angular interfaces.
E.g.
[JsonPropertyName("ProductsList")]
public List<ProductModel> Products { get; set; }
Note: Keep in mind that .NET5+ (Asp.Net Core) does not serialize model properties PascalCase if they are named PascalCase, instead the default strategy is to turn them into camelCase keys for serialization. This can be configured.

Related

How to create an rest api which accepts nested api as request

I am creating a rest api in spring boot as well as in jersey. I need to pass a nested JSON structure as request. I have no idea how to do it.
The nested structure is below,
{
"student": "",
"groupId": "a1",
"standard": "Fifth",
"isPassed": true,
"section": "A",
"data": {
"name": "Abcd",
"age": "11"
},
"additional": {
"Personal": {
"1": {
"address": {
"Home": [
"xys"
],
"Permanent": [
"xyz"
],
"Language": [
"English",
"French"
]
},
"street": "5",
"Mother": null,
"Father": null
}
}
"state": "xyz",
"Sibblings": true
}
}
I am expecting the rest call to accept this structure.
You can try something like this, first create request dto which will map the json to the DTO
import java.util.List;
public class RequestDTO {
private String student;
private String groupId;
private String standard;
private Boolean isPassed;
private String section;
private UserData data;
private Additional additional;
public String getStudent() {
return student;
}
public void setStudent(String student) {
this.student = student;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getStandard() {
return standard;
}
public void setStandard(String standard) {
this.standard = standard;
}
public Boolean getPassed() {
return isPassed;
}
public void setPassed(Boolean passed) {
isPassed = passed;
}
public String getSection() {
return section;
}
public void setSection(String section) {
this.section = section;
}
public UserData getData() {
return data;
}
public void setData(UserData data) {
this.data = data;
}
public Additional getAdditional() {
return additional;
}
public void setAdditional(Additional additional) {
this.additional = additional;
}
}
class UserData {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Additional{
private Personal personal;
private String state;
private Boolean Sibblings;
public Personal getPersonal() {
return personal;
}
public void setPersonal(Personal personal) {
this.personal = personal;
}
}
class Personal{
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
class Address{
private List<String> Home;
private List<String> Permanent;
private List<Language> Language;
public List<String> getHome() {
return Home;
}
public void setHome(List<String> home) {
Home = home;
}
}
enum Language{
English,French;
}
Second create a API handler which will accept this request
#RestController
#RequestMapping("/api")
public class AdminController {
#RequestMapping(value = "/test", method = RequestMethod.POST)
public RequestDTO postData(#RequestBody RequestDTO requestDTO) {
logger.info("Body---->", requestDTO);
return requestDTO;
}
}
You can test it via below curl
curl -X POST \
http://localhost:<PORT>/<context>/api/test \
-H 'Content-Type: application/json' \
-H 'Postman-Token: 7b66a9cf-8b69-4555-9bb2-1c186bff368d' \
-H 'cache-control: no-cache' \
-d '{
"student": "",
"groupId": "a1",
"standard": "Fifth",
"isPassed": true,
"section": "A",
"data": {
"name": "Abcd",
"age": "11"
},
"additional": {
"Personal": {
"address": {
"Home": [
"xys"
],
"Permanent": [
"xyz"
],
"Language": [
"English",
"French"
]
},
"street": "5",
"Mother": null,
"Father": null
},
"state": "xyz",
"Sibblings": true
}
}'
I will suggest you to go though offical docs for better understanding
class Data
{
private String name;
private Integer age;
}
class Student{
private String student;
private String groupId;
private String standard;
private Boolean isPassed;
private String section;
private Data data;
private Additional additional;
}
Here is something to get started with. Further nesting has to be done the similar way

Spring Boot Json Format

I want to create the Json Format as Shown below by using SpringBoot.
[
{
"name": "foo",
"albums": [
{
"title": "album_one",
"artist": "foo",
"ntracks": 12
},
{
"title": "album_two",
"artist": "foo",
"ntracks": 15
}
]
},
{
"name": "bar",
"albums": [
{
"title": "foo walks into a bar",
"artist": "bar",
"ntracks": 12
},
{
"title": "album_song",
"artist": "bar",
"ntracks": 17
}
]
}]
Please help me and please refer spring boot application which helps to create Json format as similar.
You don't need spring boot for this, you can do it using jackson.
You just need to define bean like:
public class ArtistInfo {
private String name;
private List<Album> albums;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Album> getAlbums() {
return albums;
}
public void setAlbums(List<Album> albums) {
this.albums = albums;
}
public static class Album {
private String title;
private String artist;
private int ntracks;
public Album(String title, String artist, int ntracks) {
super();
this.title = title;
this.artist = artist;
this.ntracks = ntracks;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public int getNtracks() {
return ntracks;
}
public void setNtracks(int ntracks) {
this.ntracks = ntracks;
}
}
}
Now you can use Jackson object mapper to produce JSON:
Initialize List of ArtistInfo
ObjectMapper mapper = new ObjectMapper();
List<ArtistInfo> artistInfos = initData();
String json = mapper.writeValueAsString(artistInfos);
System.out.println(json);
If you using this with Spring REST controller, spring will produce json if you return List of ArtistInfo

Supplied parameters do not match any signature of call target on api call angular4

I am consuming an api to Covalent UI, on user service. Which needs to post some data from an endpoint to the table as illustrated on the example from the GitHub.
Here is the modification I have made to the service.
import { Provider, SkipSelf, Optional, InjectionToken } from '#angular/core';
import { Response, Http } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { HttpInterceptorService, RESTService } from '#covalent/http';
import { ApiService } from '../../../../services/api.service';
import { AuthService } from '../../../../services/auth.service';
export interface IUser {
_id: string;
email:string;
createdAt: Date;
profile: {
name: string;
gender: string;
location: String;
picture: {
// data: Buffer;
contentType: string;
}
}
}
export class UserService extends RESTService<IUser> {
constructor(private _http: HttpInterceptorService, api: string,
private authService: AuthService,
private api2: ApiService,) {
super(_http, {
baseUrl: api,
path: '/dashboard/users',
});
}
staticQuery(): Observable<IUser[]> {
// return this._http.get('data/users.json')
// .map((res: Response) => {
// return res.json();
// });
return this.api2.get('auth/account/users')
.map((res: Response) => {
return res.json();
});
}
}
export const USERS_API: InjectionToken<string> = new InjectionToken<string>('USERS_API');
export function USER_PROVIDER_FACTORY(
parent: UserService, interceptorHttp: HttpInterceptorService, api: string): UserService {
return parent || new UserService(interceptorHttp, api);//<---- This is where I get the error mention.
}
export const USER_PROVIDER: Provider = {
// If there is already a service available, use that. Otherwise, provide a new one.
provide: UserService,
deps: [[new Optional(), new SkipSelf(), UserService], HttpInterceptorService, USERS_API],
useFactory: USER_PROVIDER_FACTORY,
};
JSON api data
[
{
"_id": "59d665c3acbde702b47d3987",
"updatedAt": "2017-10-07T17:23:00.498Z",
"createdAt": "2017-10-05T17:02:59.526Z",
"email": "me#mail.com",
"password": "$2a$05$z1mRUWqqUfM8wKMU/y9/sOLssAKcV7ydxi0XJyTR1d3BI2X7SSsoy",
"tokens": [],
"role": "admin",
"__v": 0,
"profile": {
"name": "F.name L.name",
"gender": "Female",
"location": "my place",
"avatar": {
"contentType": "image/png",
"data": "iVBORw0KGgoAAAANSUhEUgAAAaYAAAFmCAYAAAAmm....."
}
}
}
]
Am not sure what am doing wrong, I will appreciate your comment for this fix.
I get the error bellow.
users/services/user.service.ts (51,20): Supplied parameters do not match any signature of call target.
From this line of code
As #Philipp mentioned in the comments.
The class UserService expects 4 arguments in the constructor, but you are only providing 2 in the USER_PROVIDER_FACTORY function.
Therefore your factory should be defined:
export function USER_PROVIDER_FACTORY(
parent: UserService, interceptorHttp: HttpInterceptorService, api: string,
authService: AuthService, api2: ApiService
): UserService {
return parent || new UserService(interceptorHttp, api, authService, api2)
}

Angular2 mapping of nested JSON arrays to model

I am trying to map the received JSON-data on my created Models. The problem is, that the JSON-data has nested arrays. So it is not possible to map my data with the way I am trying to. Is there a mistake in my way or is there a better way to map my JSON-data ?
JSON-Data
{
"data": {
"apiName": "test-application",
"stages": [
{
"stage": "prod",
"id": "xxxxxxxx",
"methods": [
{
"id": "xxxxxx",
"path": "/users/create",
"httpMethods": [
"GET"
],
"methodName": "testMethod",
"url": "https://xxxx/xxxxx/xxxxxx"
}
]
},
{
"stage": "dev",
"id": "xxxxxxx",
"methods": [
{
"id": "xxxxxxx",
"path": "/users/create",
"httpMethods": [
"GET"
],
"methodName": "testMethod",
"url": "https://xxxxx/xxxxxx/xxxx"
}
]
}
]
}
}
Models:
import {ApiStage} from "./ApiStage";
export class Api {
constructor(values: Object = {}){
Object.assign(this, values);
}
public apiName: string;
public stages: ApiStage[];
}
import {ApiMethod} from "./ApiMethod";
export class ApiStage {
constructor(values: Object = {}){
Object.assign(this, values);
}
public stage: string;
public id: string;
public methods: ApiMethod[];
}
export class ApiMethod {
constructor(values: Object = {}){
Object.assign(this, values);
}
public id: string;
public path: string;
public httpMethods: string[];
public methodName: string;
public url: string;
}
HTTP-method in service:
getApi() {
return this.http.post(this.url, this.data, {headers: this.headers})
.map(this.extractData)
.map(api => new Api(api))
.catch((error: any) => Observable.of(error.json().error || 'Server error'));
}
private extractData(res: Response) {
let body = res.json();
return body.data || {};
}
JSON has just a very limited set of data types - string, number, boolean, array, object. If you want to convert a JSON object tree to a tree of objects of your custom classes, it's necessary to do it recursively and with creating correct objects - not working with objects that just look like being of your classes.
This process can be tedious and error prone, so it's better to use a library such as Class transformer (https://github.com/pleerock/class-transformer) which can do it for you. You just annotate your classes with decorators (such as #Type(...)) and then you can transform plain JSON objects using plainToClass() method or serialize real objects to JSON using classToPlain().

Using class and property names as output in JSON

I have this DTO:
public class Post
{
public int Id { get; set; }
public string Message { get; set; }
public DateTime CreatedDate { get; set; }
}
Then i have a route in servicestack that return a list of this DTO.
Method signature looks like this: public IList<Post> GetAllPost()
When getting result from this route my json look like this:
[3]
0: {
Id: 2
Message: "itworks1"
CreatedDate: "/Date(1367264995010+0200)/"
}-
1: {
Id: 3
Message: "itworks2"
CreatedDate: "/Date(1367265002050+0200)/"
}-
2: {
Id: 4
Message: "itworks3"
CreatedDate: "/Date(1367265006767+0200)/"
}
However i would like the JSON output to look like this:
posts
post: {
Id: 2
Message: "itworks1"
CreatedDate: "/Date(1367264995010+0200)/"
}-
post: {
Id: 3
Message: "itworks2"
CreatedDate: "/Date(1367265002050+0200)/"
}-
post: {
Id: 4
Message: "itworks3"
CreatedDate: "/Date(1367265006767+0200)/"
}
Is this possible with the servicestack serializer?
Try wrapping your response in an object:
public class PostListResponse
{
public List<Post> Posts { get; set; }
}
...
public PostListResponse GetAllPosts()
Then your json should look like this:
{
"posts":[
{
"id":4,
"message":"intworks3",
"createdDate":"/Date((1367265006767+0200)/"
},
{
"id":5,
"message":"intworks4",
"createdDate":"/Date((1367265006767+0200)/"
},
...
]
}