Optimization-Writing APIs in Angular Part 3

Pawan Kumawat
4 min readSep 16, 2024

--

optimized-code-in-angular

Again, How academic and real-world cases can be radically different. We’ll understand it by very simple example of “Consuming an API in Angular Component”. We will start from academic example and incorporate real world use cases, code it like an newbie [in left of the image], and evolve from there to Robust code [in the right of the image].

Let’s start with an academic example.

this.sampleService.isOrderInvoicingPossible(this.orderId).subscribe();

Above code is simple. We are calling isOrderInvoicingPossiblemethod fromSampleServiceand subscribing it onto component.

Change 1 — We should show spinner or loader until we get the data.

    this.spinnerService.showSpinner();
this.sampleService.isOrderInvoicingPossible(this.orderId).subscribe(
(response) => {
this.data = response.result;
this.spinnerService.hideSpinner();},
(error)=>{this.spinnerService.hideSpinner();}
)

Change 2 — if we get null response, we should handle it.

  this.spinnerService.showSpinner();
this.sampleService.isOrderInvoicingPossible(this.orderId).subscribe(
(response) => {
this.spinnerService.hideSpinner();
if (!response) {
this.notificationService.error('No response received');
return;
}
this.data = response.result;
},
(error)=>{this.spinnerService.hideSpinner();}
)

Change 3 — if you get error in response we should be handle it.

    this.spinnerService.showSpinner();
this.sampleService.isOrderInvoicingPossible(this.orderId).subscribe(
(response) => {
this.spinnerService.hideSpinner();
if (!response) {
this.notificationService.error('No response received');
return;
}
if (response.msgType == 'ERROR') {
this.notificationService.error(response.msg);
return;
}
this.data = response.result;
},
(error)=>{this.spinnerService.hideSpinner();}
)

Change 4 — if you get warning and info then those message should be handled. If you get successful call then don’t show success message as usually we don’t show success message on load of a component.

this.spinnerService.showSpinner();
this.sampleService.isOrderInvoicingPossible(this.orderId).subscribe(
(response) => {
this.spinnerOverLay.hideSpinnerOverlay();
if (!response) {
this.notificationService.error('No response received');
return;
}
if (response.msgType == 'ERROR') {
this.notificationService.error(response.msg);
return;
}
this.data = response.result;
if (response.msgType == 'SUCCESS') {
// Do nothing as we don't want success mesg on Load of component
} else {
this.notificationService.info(response.msg);
this.notificationService.warning(response.msg);
}
},
(error) => {
this.spinnerOverLay.hideSpinnerOverlay();
this.notificationService.error(error);
},
() => {}
);

You can see how simple code converted to complicated one just to cater the basic requirement. Now if you ask an amateur Angular developer, he’ll call this code as robust code. But this code is suffering from few problems. Lets have a look on it and refactor our code.

Improvement 1- Handling null response on client side. This is not responsibility of client but server. Because as per

Postel’s Law, also known as the Robustness Principle, is a design guideline for software that states “be conservative in what you send, be liberal in what you accept”.

That mean if your API promises an object in reponse then you should get that object in any condition instead of null. Handling null is one of the main reason of code smell.

So in our case, the response object is as below.

export class Result<T> {
result: T;
msgType: string;
msg: string;

constructor(obj) {
this.result = obj.result;
this.msgType = obj.msgType;
this.msg = obj.msg;
}
}

Here client is expecting Result type of object having three properties namely result, msgType,msg. Hence we’ll not handle the null response avoiding the billion dollar mistake. 😉

Trivia- Tony Hoare, the inventor of null references, called it his "billion-dollar mistake." He introduced null in 1965 while working on ALGOL W. Hoare later regretted it due to the many software issues it caused.

if (!response) {// Should not be handled on client
this.notificationService.error('No response received');
return;
}

Now our code shapes in following form.

this.spinnerService.showSpinner();
this.sampleService.isOrderInvoicingPossible(this.orderId).subscribe(
(response) => {
this.spinnerOverLay.hideSpinnerOverlay();
if (response.msgType == 'ERROR') {
this.notificationService.error(response.msg);
return;
}
this.data = response.result;
if (response.msgType == 'SUCCESS') {
} else {
this.notificationService.info(response.msg);
this.notificationService.warning(response.msg);
}
},
(error) => {
this.spinnerOverLay.hideSpinnerOverlay();
this.notificationService.error(error);
},
() => {}
);

Another problem that this code is suffering from is that it’s doing overwork. we are handling the messages right in the component. It can be delegated to some other service. Keeping SRP in mind.

SRP (Single Responsibility Principle) states that a class or module should have only one reason to change, meaning it should have only one responsibility or job.

@Injectable({
providedIn: 'root',
})
export class MessageHandlerService {
notificationService = inject(NotificationService);
constructor() {}
handleMessageWithoutSuccessAndError(result: Result<any>) {
let serverMsg = result.msgType;
switch (serverMsg) {
case 'WARNING':
this.notificationService.warning(result.msg);
break;
case 'INFO':
this.notificationService.info(result.msg);
break;
}
}
}

We refactored message handling into a service MessageHandlerService which is specialized into handling the messages.

Now our client code becomes much leaner.

    this.spinnerService.showSpinner();
this.sampleService.isOrderInvoicingPossible(this.orderId).subscribe(
(response) => {
this.spinnerOverLay.hideSpinnerOverlay();
this.messageHandlerService.handleMessageWithoutSuccessAndError(response)
if (response.msgType == 'ERROR') {
this.notificationService.error(response.msg);
return;
}
this.data = response.result;
},
(error) => {
this.spinnerOverLay.hideSpinnerOverlay();
this.notificationService.error(error);
},
() => {}
);

Still this code is suffering from Readability, Maintainability issues. For the sake of simplicity we will improve this code in our next blog as this blog is getting lengthier.

Thank you for reading this piece. I hope you found it useful!

Please subscribe/follow/like/clap👃. It encourages me to write more such blogs.

I’ve created an Angular Course on Udemy which covers many practical problems and solutions in Angular. It could be a stepping stone in your professional Angular Journey. Please take a look.

Angular-Practicals

You can also watch/subscribe my free YouTube channel.

--

--

No responses yet