- Home
- >
- DevOps News
- >
- Error Handling from Backends to the Frontend – InApps 2022
Error Handling from Backends to the Frontend – InApps is an article under the topic Devops Many of you are most interested in today !! Today, let’s InApps.net learn Error Handling from Backends to the Frontend – InApps in today’s post !
Read more about Error Handling from Backends to the Frontend – InApps at Wikipedia
You can find content about Error Handling from Backends to the Frontend – InApps from the Wikipedia website
In the 1990s, my Mac OS 7.5.1 would generate an error like this:
Why did I have to reboot? And so often! The errors were ambiguous and modern exception handling didn’t exist yet. In Windows 98, you’d get the same ambiguous “blue screen of death.” The reason was because Windows/Macintosh used a shared memory model before protected memory existed, so it was easy for an application to overwrite system memory and crash the kernel. Operating systems have evolved since then, and we’re all happier for it.
Errors were quite frequent and annoying in the ’90s, always requiring a reboot. When a memory error happened, you’d get ID = -1 or a hex memory address in Windows corresponding to the cause. These were called error codes, but they weren’t exceptionally helpful or user friendly unless you were an expert developer.
The Old Way of Handling Errors
Jonathan Kelley
Jonathan has been a technologist for 14 years, with a focus on DevOps for half of that. He’s currently a site reliability engineer at LogDNA, where he contributes his expertise about Linux, Kubernetes, networking and cloud infrastructure.
Imagine if you had a C function that took as arguments an array/list of integers and a single integer, and then performed a search. It should return the index of the first match in the index. But what if it didn’t? You’d return -1 or something. That makes error handling simple, right?
The problem with this approach is that every caller has to check the return function and handle the error on its own. Lots of checks and “if else” statements in your code will make tons of boilerplate that distract you from the actual business logic. The code was terrible to read and maintain.
All too often a return ID was -1, which meant “something broke, but I don’t know what.” What do you do then?
Modern Exceptions (Try) to Save the Day
Exceptions exist to solve all the problems mentioned above. An exception can interrupt software control flow and bubble up to the user with informative data. This is great, but to most users it won’t mean much of anything.
When designing your application, always try to catch exceptions you think you’d encounter and then have a generic catchall for cases where unknown problems can be caught. Perform a logging action that’s user-informative or has some other value, so the end user can troubleshoot the cause.
To catch an exception in Python using the HTTP requests library, you could do something like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import requests url = ‘http://www.google.com/bogus’ try: r = requests.get(url,timeout=3) r.raise_for_status() except requests.exceptions.HTTPError as e: print (f‘Http Error: {e}’) exit(1) except requests.exceptions.ConnectionError as e: print (f‘Connect Error: {e}’) exit(1) except requests.exceptions.Timeout as e: print(f‘Timeout Error: {e}’) exit(1) except requests.exceptions.RequestException as e: print(f‘Unknown Error: {e}’) exit(1) except Exception as e: print(f‘Unknown Exception: {e}’) exit(1) |
This is what you’d see when you visit a non-existent URL at Google:
Http Error: 404 Client Error: Not Found for url:http://www.google.com/bogus
See? Makes a lot more sense than Python’s uncaught exception handler (below):
Traceback (most recent call last): File “/tmp/fail.py”, line 4, in <module> r.raise_for_status() File “/usr/local/lib/python3.9/site-packages/requests/models.py”, line 943, in raise_for_status raise HTTPError(http_error_msg, response=self) requests.exceptions.HTTPError: 404 Client Error: Not Found for url: http://www.google.com/bogus |
You want to handle all exceptions, even if it’s just to display a friendly error message and exit the program anyway.
Good exception handling should also be used to free up resources, file resources, locks or other things that could break future execution. A super-simple example (don’t do this in practice in Python, you should use Context Manager instead) is to perform something like:
<br />
try:
<br />
myfile.write(‘the answer to life is: ‘)
<br />
myfile.write(42) # raises TypeError
<br />
except IOError as e:
<br />
print(f’Could not write to file: {e}’)
<br />
finally:
<br />
myfile.close() # will be executed before TypeError is propagated
myfile = open(‘test.txt’, ‘w’) try: myfile.write(‘the answer to life is: ‘) myfile.write(42) # raises TypeError except IOError as e: print(f‘Could not write to file: {e}’) finally: myfile.close() # will be executed before TypeError is propagated |
Always Use the Most Specific Exception
The more explicit the exception, the better you’re handling errors in code. If your code is using generic try / except blocks everywhere without a specific exception to trap, you have no control over how a specific exception is handled. This also makes exceptions unknown to the caller, which is terrible if a user or developer doesn’t understand the failure modes for your library. You should also investigate the libraries you’re using and understand the exceptions they might throw, so you can take action.
Likewise, if you’re developing an application, raise specific exceptions. Raising a generic exception makes your code brittle for error handling by downstream developers. You want your calling functions/methods to be able to handle exceptions and hopefully without their own specific checks around your library’s function.
Never Log and Re-Throw an Exception
Here’s an example where you carelessly casted a long integer as a string and perform the “catch and throw” anti-pattern. I’ve seen this a lot in Java code for some reason, so here it is:
try { new Long(“some_string”); } catch (NumberFormatException e) { log.error(e); throw e; } |
The problem is you get multiple errors for the same exception; it’s just ambiguous and unnecessary. The extra stack trace doesn’t add any new information, other then to expose the entire Java stack that called it.
17:44:28,945 ERROR TestExceptionHandling:65 – java.lang.NumberFormatException: For input string: “some_string” Exception in thread “main” java.lang.NumberFormatException: For input string: “some_string” at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Long.parseLong(Long.java:589) at java.lang.Long.(Long.java:965) at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63) at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58) |
If you want to add a stack trace with the error, throw a custom exception that has useful information for your logging library:
public void wrapException(String input) throws CrazyCustomException { try { // do something } catch (NumberFormatException e) { throw new CrazyCustomException(“I think you did something bad.”, e); } } |
Handling Frontend Exceptions
A lot of frontend applications are designed with an optimistic approach of assuming a backend always works, but that’s never a 100% guarantee. Even bug-free backends run on systems infrastructure that will eventually fail. I’ve been a systems engineer and site reliability engineer and seen so many failures in my career, that I expect all systems to fail, at least partially, sometime in their production life.
Handling errors on the frontend is critical to user experience and functionality. How can a support staff understand and support a product when it breaks? How can QA make bug tickets if you don’t have anything to show when errors happen?
Types of Frontend Errors
Here are the usual errors you’ll see:
- Backend availability errors: The system that a frontend consumes goes down for some reason. Likely a server crash, deployment or unexpected maintenance.
- Authentication/authorization errors: This happens when a user doesn’t have permission.
- Input errors: This happens if validation is missing in the frontend but gets caught or thrown by the backend. Could be input validation or unique constraint errors in a database, for example.
- Unknown errors: Sometimes errors just happen. API 500 errors due to an unhandled code exception can always happen, because sometimes you just forget to predict where backend code fails.
How Frontends Break With Unhandled Backend Errors
Frontend apps usually have little in the way of handling the backend errors. I’ve seen the following modes of failure in JS webapps:
- If the error happens during framework initialization, users may see a white page.
- The framework stops working with no indication of why. The user tries an action again, but either the web page is locked up or nothing happens. The user refreshes the web page and hopefully gets a working application.
- The framework keeps running but unexpected things happen. The user likely tries over and over, hopefully getting the response they want, but possibly causing unintended side effects on the backend. A terrible example would be hitting a payment gateway and getting double or triple charged!
Put Errors in Context For the User
You want to start by designing your backend to handle errors as gracefully as possible, to give something for the frontend to present to a user. When designing a REST API for instance, instead of just returning 500, check out the list of available HTTP codes in the Mozilla developer center.
I also suggest returning a body instead of an empty document with error generation so the web application can “bubble up” messages to a user. Something like this is excellent:
{ “error”: { “code”: 500, “reason”: “Payment gateway timeout, try again later” } } |
An error like this is great, because your application can tell the user something useful. So if they contact you for support, you’ll know exactly where your app went wrong. This is way better than the classic “Oops! An error occurred!”
Frontend Error Handling is Vital
It’s best to tell a user what went wrong and hint at what will fix the error for them. Here are some keywords I’d use to let a user make sense of frontend errors.
- Invalid input. If the backend had an input validation error, tell the user.
- Try again later. Something broke, but maybe it’ll work later. This lets the user know that this problem isn’t their fault and might resolve.
- Unknown error. Please contact support. Something broke badly, so maybe you should contact a support team so they can determine the next steps.
You should write your frontend to use json stringify to parse the backend errors and return with valid context and messaging for the user.
Conclusion
Just keep in mind that errors always happen, perfect test coverage or not. The question is what will you do to handle them with excellence? Will your users be able to take action to save the user experience when errors occur? Will they have a good user experience even when the app fails?
Make it easier for users to create helpful GitHub issues or send useful messages to a support team. When your junior developer reads a bug ticket, will it be clear what happened without having to spelunk through the entire codebase?
Handling errors appropriately keeps our users happy.
Photo by Yan Krukov from Pexels.
Source: InApps.net
List of Keywords users find our article on Google:
404 http response |
what is http status 404 |
response code 404 |
http status 404 |
for input string java |
python memoryerror |
custom os can cause critical problems |
numberformatexception |
java throw exception |
wawa app error codes |
java lang |
tmp recruitment |
windows 98 protection error |
python print error stack |
raise_for_status |
java long |
front end module industry |
404 error http |
404 http status |
exit wikipedia |
backend for frontend wikipedia |
python try si except |
in the context of data services an unknown internal server error occurred |
cloud print wikipedia |
generic system error |
raise_for_status example |
jonathan day wikipedia |
except httperror |
an unhandled exception occurred: dev-server address info is not defined. |
an unknown error occurred |
line an unknown error occurred |
case handler jobs |
python print exception |
python requests.exceptions.connectionerror |
tmp consulting |
java lang numberformatexception for input string |
throw exception python |
java lang string |
exception handling in java |
exception in thread main |
exit code 65 |
error template parse errors |
front end error logging |
facebook backend |
java.lang.numberformatexception: for input string: |
throw error python |
python exception message |
python throw exception |
client-side exception has occurred |
бэкэнд фронтэнд |
backend frontend |
http return code 404 |
http response code 404 |
http 404 error |
404 error design |
404 error page design |
404 http code |
404 page design |
Let’s create the next big thing together!
Coming together is a beginning. Keeping together is progress. Working together is success.