Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I map http request response to my defined object in TypeScript

I'm getting to know Angular, TypeScript and RxJS. I have an http request that returns a JSON. In this JSON there is data that I need to construct my defined object. Let's say, that my object is this:

export class RegularUser {
    constructor(
        public id: number,
        public firstName: string,
        public lastName: string,
        public token: string
    ) {}
}

Now, I am sending a request to some API, which returns data in this format:

{
    success: boolean,
    uid: number,
    first_name: string,
    last_name: string,
    cid: number,
    rights: number[]
    token: string
}

I have the HttpClient service, so I thought I would do:

this.httpClient.get(
    'http://api.example.com/api/get_user'
).pipe(
    tap((receivedData: Response) => console.log(receivedData)),
    map((receivedData: Response) => {
        return new RegularUser(
            receivedData.uid, 
            receivedData.first_name, 
            receivedData.last_name, 
            receivedData.token);
    })
);

But for TypeScript, the receivedData object doesn't have above-listed params. Do I have to create an interface for the API response and then map it to my RegularUser object?

like image 773
george007 Avatar asked Aug 23 '18 16:08

george007


People also ask

How do I create a HTTP request in TypeScript?

The http requests in TypeScript can be placed using a function called fetch() function. The fetch() function takes two parameters, namely URL and options and returns a Response object.

How do I map JSON to interface TypeScript?

To convert JSON to the interface, the developer does not need to do anything. simply write code that follows some rules to allow the typescript compiler to do the conversion. First, the Interface is defined with properties the same as JSON fields.

How would you write code to modify the response from an HTTP GET?

catch( (error: Response) => { return Observable. throw(error); } );


3 Answers

You can specify a type for get() such as an interface. Why an intermediary/additional interface may be warranted for separation of concerns in your situtation is that get() with a type will not new up an instance of class RegularUser. An intermediary/additional interface can be created with properties you expect from the server response that will be used to create an instance of your end class:

interface Foo {
  uid: number,
  first_name: string,
  last_name: string,
  token: string
}

this.httpClient.get<Foo>(
    'http://api.example.com/api/get_user'
).pipe(
    tap((receivedData: Foo) => console.log(receivedData)),
    map((receivedData: Foo) => {
        return new RegularUser(
            receivedData.uid, 
            receivedData.first_name, 
            receivedData.last_name, 
            receivedData.token);
    })
);

If you do not need to new up an actual instance of class RegularUser, it may be enough it to just have it as an interface or class with properties:

this.httpClient.get<RegularUser>(
    'http://api.example.com/api/get_user'
).pipe(
    tap((receivedData: RegularUser) => console.log(receivedData))
);

Hopefully that helps!

like image 148
Alexander Staroselsky Avatar answered Sep 20 '22 20:09

Alexander Staroselsky


Instead of constructor, use interface which is a better alternative. So IDE can enable code autocompletion using the Language Service and wrong naming of properties can be avoided.

export interface RegularUser {
    success: boolean;
    uid: number;
    first_name: string;
    last_name: string;
    cid: number;
    rights: number[];
    token: string;
}

In service:

this.httpClient.get<RegularUser>(
    'http://api.example.com/api/get_user'
).pipe(
    tap((receivedData: RegularUser) => console.log(receivedData))
);
like image 25
Suresh Kumar Ariya Avatar answered Sep 21 '22 20:09

Suresh Kumar Ariya


You can create your own Response interface by using:

export interface MyResponse {
  success: boolean,
  uid: number,
  first_name: string,
  last_name: string,
  cid: number,
  rights: number[]
  token: string
}

And then import it into your service:

import { MyResponse } from '../some/path/filename.ts'; 

But you can also include it in your service itself, so you can skip 'export'.

You can just use it just like your current Response interface:

(receivedData: MyResponse)

Note: you can give it any name you want (use TitleCase for consistency). You can also use names already used by Angular, which will then be overwritten, but that's not recommended. See comments.


You may have to make some properties optional (?:), otherwise you may get a red line indicating that 'some properties are missing' if not all are used:

...
success?: boolean,
...

Or, you can just remove the warning by making it type any, but that's not recommended:

(receivedData: any)
like image 31
Jeffrey Roosendaal Avatar answered Sep 22 '22 20:09

Jeffrey Roosendaal