I am trying to cast a response object from an HTTP Post request in my angular project to a Person
class that I have defined. I have defined a generic post method in an HTTP Service, and am calling that in my person service with the generic replaced with Person
. So, I would think, since I have done that the HTTP response
should be a Person
, but it's not - it's just an Object
. I need it to be a Person
because my Person class has some custom logic on it that I need to access. I could write a helper method in my person service, but I feel like this should work - especially since VS Code intellisense says that the response
in my component is a Person
when I hover my mouse over it.
Here is my code:
http.service.ts
@Injectable()
export class HttpService {
baseUrl = 'https://baseurl.com';
constructor(private http: HttpClient) { }
post<T>(endpointUrl: string, body: any): Observable<T> {
const fullUrl = this.baseUrl + endpointUrl;
return this.http
.post<T>(fullUrl, body)
.pipe(
map(response => response as T)
);
}
}
person.service.ts
@Injectable()
export class PersonService {
constructor(private httpService: HttpService) { }
newPerson(body: Person): Observable<Person> {
return this.httpService.post<Person>('/people', JSON.stringify(body));
}
}
person.component.ts
@Component({
selector: 'app-person',
templateUrl: './person.component.html',
styleUrls: ['./person.component.css'],
})
export class PersonComponent {
person: Person = new Person();
onSubmit(id: number) {
if (id == 0) {
console.log(this.person); // Person {id: 0, ...
console.log(this.person.constructor.name); // Person
let body = this.person.fromFormGroup(this.formGroup);
this.personService.newPerson(body)
.subscribe(response => { // VS Code intellisense says this: (parameter) response : Person
this.person = response as Person;
console.log(this.person); // {id: 72, ...
console.log(this.person.constructor.name); // Object
// Trying a different way
this.person = <Person>response;
console.log(this.person); // {id: 72, ...
console.log(this.person.constructor.name); // Object
})
}
}
}
newPerson(body: Person): Observable<Person> {
return this.httpService.post<Person>('/people', JSON.stringify(body));
}
The HttpClient.post()
method can not return type Person
, because JSON responses are just cast to types. The default type is just Object
, but you need to create a new instance of Person
for each response. If the type was an interface then there would be no problem.
You can create a new instance of Person
and then assign the values to that instance.
newPerson(body: Person): Observable<Person> {
return this.httpService.post('/people', JSON.stringify(body)).pipe
map(value => Object.assign(new Person(), value)
);
}
Response from the http service will be a json object which is deserialised to a javascript object. Your person service cannot convert JavaScript object received in the api response to person object out of the box. Remember typescript code is transpiled to javascript code. To convert the javascript object to your Person class object you will have to manually instantiate your class object and fill the properties from the response of the api by projecting the response to person object. You can do the following [notice the map operator used to project the response to person]-
person.service.ts
@Injectable()
export class PersonService {
constructor(private httpService: HttpService) {}
newPerson(body: Person): Observable<Person> {
return this.httpService.post<Person>('/.people', JSON.stringify(body))
.pipe(
map(response => {
const person = new Person();
//fill the person props from response
return person;
}),
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With