How do I map http request response to my defined object in TypeScript
Solution 1
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!
Solution 2
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))
);
Solution 3
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)
george007
Having fun coding at WeNow.com to pay my bills. Jogging, reading books and watching movies to relax. Reading magazines and browsing blogs to stay up to date. Gadgets enthusiast.
Updated on July 09, 2022Comments
-
george007 almost 2 years
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 myRegularUser
object? -
george007 over 5 yearsThank you for your answer. I will need an instance of the
RegularUser
object to share it, so your first option seems better. However, as I understand yourUser
interface should have other properties, right? -
george007 over 5 yearsThank you for your answer. I understand that with this approach i will get the mapping done by Angular, but I actually need an instance of the
RegularUser
object to be able to share it. And I would like it to have only the params that I defined. -
george007 over 5 yearsThank you for your answer. So I have to create an interface. Can I do it in the service file where I have this http request? Also, the name of the interface shouldn't be
Response
, right? -
Jeffrey Roosendaal over 5 yearsUpdated, there you go.
-
Alexander Staroselsky over 5 yearsI'd add just add whatever properties you specifically need from the server response, no more no less. You can always log the response and add anything else attached to that object, but I'd personally just be specific to the data structure you need to use.
-
Alexander Staroselsky over 5 yearsBe careful with naming the interface
Reponse
as Angular's HttpClient Response may get accidentally pulled in by the IDE to existing HttpClient imports or if HttpClientResponse
is needed, it will need to be aliased if both are present in the same file.