-1

I'm new to Angular4 from a Python background and trying to understand the best pattern for creating a HTTPClient Service then consuming that service in a component.

My service looks like this:

@Injectable()
export class DatasetService {
  constructor(private http: HttpClient) { }

  getDatasets(): Observable<Array<Dataset>> {
    // Get list of all datastes
    return this.http.get<Array<Dataset>>('http://localhost:5000/api/v2/admin/dataset/list');
  }
}

My component consumes the service as follows:

export class DataManagementComponent implements OnInit {

  constructor(private datasetService: DatasetService) { }

  ngOnInit() {
    this.datasetService.getDatasets()
      .subscribe(
        data => {
           console.log(data['datasets']);
        },
        error => {
          if (error.status === 404) {console.log('No records'); }
        });
    }
}

This works but it feels like the service is leaky as the consumer has to map the data and handle the errors. Whereas if I was doing this in Python I'd have something like:

try:
    mydata = DatasetService.getDatasets()
except as e:
    print(e)   
Iain Hunter
  • 4,319
  • 1
  • 27
  • 13

1 Answers1

1

Where and how you handle errors is totally up to you, you can catch in your service layer:

getDatasets(): Observable<Array<Dataset>> {
  // Get list of all datastes
  return this.http.get<Array<Dataset>>('http://localhost:5000/api/v2/admin/dataset/list')
   .catch(err => { 
     console.log('I caught an error');
     // maybe redirect?
     return Observable.throw(err); //option to rethrow
     //return Observable.of({isError:true, message: err.json()}); //or some standard error interface
     //return Observable.empty(); //or just swallow it
   });
}

or do it at the component level like you have, typically a user facing interface wants to know about errors, depending on the type, you have all the flexibility in the world. There isn't a right or wrong here as it depends on your app and your UI and your UX you're trying to build.

However, as for mapping data, you probably don't want to subscribe in component code, and want to use the async pipe where ever possible

dataSet$: Observable<Array<Dataset>>;
ngOnInit() {
  this.dataSet$ = this.datasetService.getDatasets()
                     .map(data => data) // optional transformation of data
                     .catch(err => Observable.throw(err)); //optional component error handling
}

then in template:

<div *ngIf="dataSet$ | async as dataSet; else loading>
  <!-- logic to display your data set goes here, can also use async in ngFor -->
</div>
<ng-template #loading>Optional Loading template...</ng-template>

Letting async handle your subscriptions is far better, it recieves the result of whatever you would have subscribed to. This guarantees subscription management is always handled properly and protects you from memory leaks. Also subscriptions using async trigger change detection and your code is simply cleaner

bryan60
  • 28,215
  • 4
  • 48
  • 65