Loading basic data from a database – done

Following the pattern from yesterday, I modified the service which gets a list of categories to get them from a database instead of a mock. As a side effect of both operations Jasmine tests are gone, because now I need to adjust them to depend on some mock Http. I’m not sure when it will be possible though – deadlines are coming… Yes, it’s the most common and the most incorrect excuse from not writing tests, but in this case I can still afford them after the end of May. No doubt I won’t finish on time, so I’ll continue afterwards to achieve something publishable.

A service communicating with a database can return errors, so I also added handling them – meaning logging the whole available stuff and displaying a gentle message for a user. For the purpose of messages and some UI elements coming soon, I’ve added a temporary constant object which acts as a source of texts, so that they are not hardcoded. I won’t provide support for foreign languages (because nobody creates several versions of an advertisement), but keeping constant strings in one place is a good practice.

In order to present a message when there is an error, I’ve designed services to return a promise with an optimistic path only. To say it simpler: an asynchronous action (a request to the API) is executed. A promise provides an interface which lets us handle two situations: when a promise is resolved (which is an arbitrary term for an optimistic path – in my case it’s when the request returns data correctly) or rejected (the pessimistic path – when an exception has been thrown or the promise has been rejected explicitly). I’ll add the rejection stuff only in components. An example for loading categories:

CategoryService:

...
@Injectable()
export class CategoryService {
    constructor(private http: Http) { }

    getCategories(): Promise<Category[]> {
        let url = Constants.urlBase + `categories`;
        return this.http.get(url).toPromise()
            .then(response => {
                let categories: any[] = response.json();
                let result: Category[] = categories.map(category => new Category(category.Id, category.Name));
                return Promise.resolve(result);
            });
    }
};

app.component, the current main one:

export class AppComponent implements OnInit {
    header = 'Addregator';
    categories: Category[];
    errorMessage: string;

    constructor(private categoriesService: CategoryService, private logService: LogService) { }

    ngOnInit(): void {
        this.categoriesService.getCategories()
            .then(categories =>
                this.categories = categories
            ).catch(reason => {
                this.logService.log(reason.json());
                this.errorMessage = TextConstants.errorOccurred;
            });
    }
}

and its poor template:

<h1>{{header}}</h1>
<ul>
	<li *ngFor="let category of categories">
<a routerLink="categories/{{category.id}}" routerLinkActive="active">{{category.name}}</a></li>
</ul>
{{errorMessage}}
<router-outlet></router-outlet>

(WordPress sucks a bit in formatting…)
then() and catch() mean resolve and reject handling respectively. As we can see, then() is doubled – the first one is in the service, the second in the component. This is chaining in practice – if everything goes well, the former then’s returned value is an input to the latter one. Otherwise only catch() from the component is called:

Error handling

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s