stringnome
stringnome

Reputation: 233

angular create model for nested JSON data

I need to create a simple crud using httpclient

How can I get the request data correctly for this nested json?

JSON

{
    "resource": {
        "date": "2018-03-28T11:30:00",
        "observation": "truck stop schedule",
        "place": "truck garage"
    },
    "errors": null,
    "message": null
}

Service

get(id: number){
    return this.http.get(environment.apiUrl + id + "/stopschedule")
    .catch(this.errorHandler);
}

delete(id: number) {
    return this.http.delete(environment.apiUrl + id + "/stopschedule")    
    .catch(this.errorHandler);
}

update(Travel, id: number) {
    return this.http.put(environment.apiUrl + id + "/stopschedule", Travel)
    .catch(this.errorHandler);
}

errorHandler(error: HttpErrorResponse) {
    return Observable.throw(error.message)
}

Model

export class Travel {
    date: Date;
    place: string;
    observation: string;
}


export class ResponseDetails { 
    errors:string;
    message : string; 
}

import { Travel} from './travel';
export class Response extends ResponseDetails{
    travel : Travel; 
}

Component.ts

//Get data
this.getData = this.travelService.get(this.id)
    .subscribe(result => this.data = result['resource'], result =>  this.erro = true);

I tried this way but my request is returning an undefined object.

Upvotes: 0

Views: 3580

Answers (4)

Giovane
Giovane

Reputation: 1451

If you'r using the HttpClient API I'd suggest you change your model to something like this:

class ServerResponse<T> {
  resource: T;
  errors: string;
  message: string;
}

class Travel {
  date: Date;
  place: string;
  observation: string;
}

Then map your server requests like:

get(id: number): Observable<ServerResponse<Travel>>{
    return this.http.get<ServerResponse<Travel>>(`${environment.apiUrl}${id}/stopschedule`);
}

Then in your component:

this.getData = this.travelService.get(this.id)
    .subscribe(
      result => this.data = result.resource,
      () =>  this.erro = true
    );

Upvotes: 0

Eliseo
Eliseo

Reputation: 57941

in the service use "map" to change the response

get(id: number){
    return this.http.get(environment.apiUrl + id + "/stopschedule")
    .map(response=>response.resource); //NOT return response, just response.resource
    .catch(this.errorHandler);
}

Upvotes: 1

Giovanni Silva
Giovanni Silva

Reputation: 714

Your API looks strange, but could be only a explanation problem. It makes sense as a response, where errors and message are in the payload, but not as post, and if that is the case, the answer by @krystianpe is the correct way, I must add that if using the new HttpClient the map from json is done automatically if angular can figure out that is a json (response-type: application/json header from server or similar).

Anyway I will quick explain on a way that I think is a better idiomatic REST API:

Creating a new schedule

POST: http://localhost/api/schedule Body: { "date": "2018-03-28T11:30:00", "observation": "create a new schedule", "place": "truck garage" }

Return all active schedule

GET: http://localhost/api/schedule

If you need filter you have two options:

  1. Simplest one is to pass parameters: http://localhost/api/schecule?active=false for example. Use angular URLSearchParams
  2. Create Request Headers for more complicated or sofisticated stuff (never saw any). Use HttpHeaders

Editing a schedule:

PUT: /api/schedule/1

Body: { "date": "2018-03-28T11:30:00", "observation": "new observation", "place": "new place" }

You have two options: 1. Pass the whole object and update all properties (simplest) 2. Pass only the properties who are being altered.

Deleting is as simple as

Delete: /api/1

If you need to vinculate what truck has the schedule you put that on the payload (body): { "date": "2018-03-28T11:30:00", "observation": "new observation", "place": "new place", "truck_id": 1 }

To start/stop a schedule, which is your main problem, I think, you have more flexibility. Here are some ways:

PUT: /api/schedule/1/start PUT: /api/schedule/1/stop

PUT: /api/schedule/1/actions BODY: {"state": "start", "when": "now"}

PUT is to indicate you are updating somehow the state of system. But that looks like you have a relationship with a "Start" object or "Actions" object and is changing this. So I whould prefer:

PUT/POST/GET: /api/schedule/1/actions/start

Use PUT to indicate the action is idempotent (which is a confuse word), that changes only the schedule and have no other side effect. Which I think is the case. Use POST to indicate a action which is not idempotent, the side effects are unknow or affect others. USE GET to invoke a action that is ready-only and has not side effects in the system (send a email for example)

You can and should, pass parameters in the body (in this case you are configuring the start parameters), except from GET (makes no sense, use URLParams)

This is explained in more detail in https://github.com/restfulobjects/restfulobjects-spec/blob/2180261f47b7e9279bdb18180ffbee1430b1e342/restfulobjects-spec.pdf?raw=true

There is a discursion in stackoverflow: REST actions and URL API design considerations

Upvotes: 0

krystianpe
krystianpe

Reputation: 136

Your result is probably not json body but whole response object so it doesn't contain resource property. To retrieve the body from response you need to call json() method:

this.getData = this.travelService.get(this.id)
  .map(response => response.json())
  .subscribe(result => this.data = result['resource'], result =>  this.erro = true);

Upvotes: 0

Related Questions