1675716120
In this article you will know how to create Drag and Drop File Upload using HTML CSS and JavaScript. Earlier I have shared many more types of Drag and Drop elements and File Upload and Preview section. This is basically a drag and drop multiple file upload that I made with javascript.
Now it’s time to create JavaScript Drag and Drop File Upload. Here I have created the basic structure by html. I designed it with css and activated this Drag & Drop or Browse – File upload with javascript.
Drag and drop file upload in JavaScript refers to the ability to select one or more files using the drag and drop gesture, and then upload those files to a server.
This feature is typically implemented using JavaScript event listeners, such as “dragover” and “drop,” that detect when a file is being dragged over a specific element on the page and when the file is dropped onto that element. Within this project () you can upload the image by selecting it and you can also upload it by drag and drop. Also here you can upload multiple images.
As you can see above this is a simple javascript drag and drop file upload project. Here I have created a small area or box. Inside that box is a button. You can select the image by clicking on that button or you can drag and drop the image into the box. Then the uploaded image can be seen in the preview box below.
Now if you want to build(How To Make A Drag-and-Drop File Uploader With javascript) this project then follow the step by step tutorial below. Here I have given you the necessary explanation and source code. A bit more JavaScript is used here. But there is no reason to worry. I have explained each code step by step and tried to explain you completely why I used that line of code.
Besides, I have given a preview after each step. Which will help you to know what kind of result will be seen after using that code.
I have created the basic structure of this Drag and drop multiple file upload using the following html and css. All the information of that box can be seen. I used white for the background color of the box and some shadows around it.
<div class="container">
</div>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
body {
background-color: #a4b7e3;
}
.container {
background-color: #ffffff;
width: 60%;
min-width: 27.5em;
padding: 3.12em 1.87em;
position: absolute;
transform: translate(-50%, -50%);
left: 50%;
top: 50%;
box-shadow: 0 1.25em 3.43em rgba(0, 0, 0, 0.08);
border-radius: 0.5em;
}
Now an input button is created to upload the file. I have created this button using HTML’s input function. For uploading image only I used accept=”image/*” which basically will help to upload image file only.
<input type="file" id="upload-button" multiple accept="image/*" />
<label for="upload-button">
<i class="fa-solid fa-upload"></i> Choose Or Drop Photos
</label>
input[type="file"] {
display: none;
}
label {
display: block;
position: relative;
background-color: #025bee;
color: #ffffff;
font-size: 1.1em;
text-align: center;
width: 16em;
padding: 1em 0;
border-radius: 0.3em;
margin: 0 auto 1em auto;
cursor: pointer;
}
Now an area is created, in which the images can be viewed i.e. image preview area is created. How images are displayed is determined by css.
<div id="error"></div>
<div id="image-display"></div>
#image-display {
position: relative;
width: 90%;
margin: 0 auto;
display: flex;
justify-content: space-evenly;
gap: 1.25em;
flex-wrap: wrap;
}
#image-display figure {
width: 45%;
}
#image-display img {
width: 100%;
}
#image-display figcaption {
font-size: 0.8em;
text-align: center;
color: #5a5861;
}
.active {
border: 0.2em dashed #025bee;
}
#error {
text-align: center;
color: #ff3030;
}
Now it’s time to implement this drag and drop multiple file uploader using javascript. Here I have given the necessary explanation, hope you will not have any difficulty in understanding.
These lines of code are assigning variables to different elements on a webpage by their ID to active Drag And Drop File Uploader in javascript. The variables are:
uploadButton
is assigned to the element with the ID “upload-button”chosenImage
is assigned to the element with the ID “chosen-image”fileName
is assigned to the element with the ID “file-name”container
is assigned to the first element with the class “container”error
is assigned to the element with the ID “error”imageDisplay
is assigned to the element with the ID “image-display”It appears that these variables will be used to manipulate these elements and their properties in later JavaScript code.
let uploadButton = document.getElementById("upload-button");
let chosenImage = document.getElementById("chosen-image");
let fileName = document.getElementById("file-name");
let container = document.querySelector(".container");
let error = document.getElementById("error");
let imageDisplay = document.getElementById("image-display");
This code defines a function fileHandler()
that takes in three parameters: file
, name
, and type
. The function checks if the file is of type image by checking the first part of the type string before “/” if it is not of type image it sets the innerText of the error element to “Please upload an image file” and returns false.
If the file is an image, it sets the innerText of the error element to an empty string and creates a new FileReader object, which reads the contents of the file as a Data URL.
When the file has been read, the onloadend
event is triggered, at this point it creates an imageContainer
element and an img
element, sets the source of the img
element to the result of the file reader, appends the img
element to the imageContainer
element, and then appends a figcaption
element containing the file name to the imageContainer
element. Finally, it appends the imageContainer
element to the imageDisplay
element.
const fileHandler = (file, name, type) => {
if (type.split("/")[0] !== "image") {
//File Type Error
error.innerText = "Please upload an image file";
return false;
}
error.innerText = "";
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = () => {
//image and file name
let imageContainer = document.createElement("figure");
let img = document.createElement("img");
img.src = reader.result;
imageContainer.appendChild(img);
imageContainer.innerHTML += `<figcaption>${name}</figcaption>`;
imageDisplay.appendChild(imageContainer);
};
};
Now Drag and Drop File Upload project upload button should be activated. This code attaches an event listener to the uploadButton
element that listens for a “change” event. When the event is fired, the function inside the event listener is executed. The function clears the content of the imageDisplay
element by setting its innerHTML to an empty string.
Then it creates an array of the files from the uploadButton
element, and for each file in that array, it calls the fileHandler()
function and passes in the file
, the file.name
, and the file.type
as the arguments.
This code is used to handle the event of a user selecting and uploading one or more image files, displaying each image file and its name on the page by calling the fileHandler
function for each file.
//Upload Button
uploadButton.addEventListener("change", () => {
imageDisplay.innerHTML = "";
Array.from(uploadButton.files).forEach((file) => {
fileHandler(file, file.name, file.type);
});
});
Now you need to define what happens when you drag the file into the Simple javascript Drag and Drop File Upload box. This code attaches an event listener to the container
element that listens for a “dragenter” event. When the event is fired, the function inside the event listener is executed. The function calls preventDefault()
and stopPropagation()
on the event object (e
) to prevent the default browser behavior and stop the event from propagating.
Then it adds a class “active” to the container
element’s classList. This code is probably used to handle the event of a user dragging an item over the container
element, indicating that the container is a valid drop target.
The class “active” is added to the container which can be used to style it and give visual feedback that the container is active and ready to accept the dragged item.
container.addEventListener(
"dragenter",
(e) => {
e.preventDefault();
e.stopPropagation();
container.classList.add("active");
},
false
);
Now you need to determine what happens if you drag leave within the HTML drag drop upload area. This code attaches an event listener to the container
element that listens for a “dragleave” event. When the event is fired, the function inside the event listener is executed. The function calls preventDefault()
and stopPropagation()
on the event object (e
) to prevent the default browser behavior and stop the event from propagating.
Then it removes the class “active” from the container
element’s classList. This code is probably used to handle the event of a user dragging an item out of the container
element, indicating that the container is no longer a valid drop target.
The class “active” is removed from the container, it can be used to style it and give visual feedback that the container is no longer active and no longer ready to accept the dragged item.
container.addEventListener(
"dragleave",
(e) => {
e.preventDefault();
e.stopPropagation();
container.classList.remove("active");
},
false
);
Upload files with Drag and Drop to determine what happens when dragover. This code attaches an event listener to the container
element that listens for a “dragover” event. When the event is fired, the function inside the event listener is executed. The function calls preventDefault()
and stopPropagation()
on the event object (e
) to prevent the default browser behavior and stop the event from propagating.
container.addEventListener(
"dragover",
(e) => {
e.preventDefault();
e.stopPropagation();
container.classList.add("active");
},
false
);
This code attaches an event listener to the container
element that listens for a “drop” event. When the event is fired, the function inside the event listener is executed. The function calls preventDefault()
and stopPropagation()
on the event object (e
) to prevent the default browser behavior and stop the event from propagating.
Then it removes the class “active” from the container
element’s classList. It then creates a variable draggedData
which holds the dataTransfer object of the event, which contains the data that was dropped onto the element. It then creates a variable files
which holds the file object from the draggedData
object. It clears the content of the imageDisplay
element by setting its innerHTML to an empty string.
Then it creates an array of the files and for each file in that array, it calls the fileHandler()
function and passes in the file
, the file.name
, and the file.type
as the arguments. This code is used to handle the event of a user dropping one or more files on to the container
element, which then calls the fileHandler
function to display the image and its name on the page.
container.addEventListener(
"drop",
(e) => {
e.preventDefault();
e.stopPropagation();
container.classList.remove("active");
let draggedData = e.dataTransfer;
let files = draggedData.files;
imageDisplay.innerHTML = "";
Array.from(files).forEach((file) => {
fileHandler(file, file.name, file.type);
});
},
false
);
Now it is determined that every time the page is loaded all the information contained in the Drag and Drop File Upload with HTML CSS JavaScript will be removed. This code assigns an anonymous function to the onload
property of the window
object, which is fired when the page has finished loading. The function sets the innerText
of the error
element to an empty string, effectively clearing any pre-existing text.
window.onload = () => {
error.innerText = "";
};
Hope you got to know from above tutorial how I created this project(Drag and Drop File Upload Using HTML,CSS & JavaScript). I have already shared many more JavaScript tutorials with you.
Be sure to comment how you liked this Drag and Drop File Upload JavaScript tutorial.
Original article source at: https://foolishdeveloper.com/
1675479180
In Python, items of iterable objects such as lists, tuples, or strings can be accessed by using their index numbers.
The index number starts from 0 and increases by 1 for each subsequent item in the object.
For example, here’s how to access the first character in a string:
# Declare a string variable
my_str = "Good Morning!"
# Print the first character in the string
print(my_str[0]) # G
The code above will print G
because it’s the first character of the string my_str
.
The error TypeError: string indices must be integers
occurs when you try to access a character in a string using a string.
For example, suppose you try to access the first character as follows:
my_str = "Good Morning!"
print(my_str['G']) # ❌
Output:
Traceback (most recent call last):
File ...
print(my_str['a'])
TypeError: string indices must be integers
To fix this error, make sure you’re passing an integer inside the square brackets.
The following three scenarios may cause this error:
The following examples show how to fix this error in each scenario
Aside from passing the index number of a character, you can also extract several characters from a string by using the slicing syntax.
The slicing syntax is as follows:
string_object[start_index:end_index]
The start_index
is the starting position of the slice and end_index
is the ending position of the slice. The two are separated using a colon (:
) operator.
When start_index
is not specified, it is assumed to be 0. If end_index
is not specified, it is assumed to be the length of the string itself.
The start_index
is included in the output, but the end_index
is excluded.
Here are some examples of slicing a string in Python:
my_str = "Good Morning!"
# return 'Morning'
print(my_str[5:12])
# return 'Good'
print(my_str[:4])
# return 'ood'
print(my_str[1:4])
# return 'ning!'
print(my_str[8:])
But when you pass a wrong slice syntax, then Python will give you a TypeError
:
my_str = "Good Morning!"
# ❌ Use a comma to separate the integers
print(my_str[5,12])
# ❌ Use a dot to separate the integers
print(my_str[5.12])
# ❌ Use a colon but enclosed in quotes
print(my_str['5:12'])
To avoid the error, make sure that the slice syntax has the correct format.
Suppose you have a dictionary object as shown below:
data = {
"name": "Nathan",
"age" : 29
}
Now let’s say you want to access the values and print them out using a for
loop:
for item in data:
print(item['name']) # ❌
The code above will cause a TypeError
because the for
loop will return the dictionary key in each iteration.
Here’s the right way for accessing a dictionary with a for
loop:
data = {
"name": "Nathan",
"age" : 29,
"location": "Japan"
}
for item in data:
print(item, data[item])
Output:
name Nathan
age 29
location Japan
Because the for
loop returns the keys, you can use it to access the dictionary values with the square brackets notation.
In Python, a JSON object is similar to a dictionary object, so you can access its values using the keys.
But at times, you might mistake a string for a JSON object:
json_str = '{"name": "Nathan","age" : 29}'
print(json_str['name']) # ❌
The json_str
object is an encoded JSON string, so trying to access the name
value as shown above will cause a TypeError
.
To fix this, you need to import the json
library and use the json.loads()
method:
import json
json_str = '{"name": "Nathan","age" : 29}'
json_obj = json.loads(json_str)
print(json_obj['name']) # Nathan
print(json_obj['age']) # 29
The loads()
method converts a JSON string into a JSON object, which enables you to access the values like a dictionary.
Keep in mind that you don’t need to call the json.dumps()
method.
The dumps()
method is used to convert an object to a JSON string. But you already have a string here, so there’s no need to call it 🤷🏻
And there you go! Now you know three common scenarios where you may cause the TypeError: string indices must be integers
in Python.
This error happens whenever you try to access a string using a string and not index numbers. It can also occur when you’re working with dictionaries and JSON objects.
The steps in this article should help you resolve the error. Happy coding! ☕️
Original article source at: https://sebhastian.com/
1675373100
A JSONDecodeError: Expecting value
when running Python code means you are trying to decode an invalid JSON string.
This error can happen in three different cases:
Case 1: Decoding invalid JSON content Case 2: Loading an empty or invalid .json
file Case 3: A request you made didn’t return a valid JSON
The following article shows how to resolve this error in each case.
The Python json
library requires you to pass valid JSON content when calling the load()
or loads()
function.
Suppose you pass a string to the loads()
function as follows:
data = '{"name": Nathan}'
res = json.loads(data)
Because the loads()
function expects a valid JSON string, the code above raises this error:
Traceback (most recent call last):
File ...
res = json.loads(data)
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
To resolve this error, you need to ensure that the JSON string you passed to the loads()
function is valid.
You can use a try-except
block to check if your data is a valid JSON string like this:
data = '{"name": Nathan}'
try:
res = json.loads(data)
print("data is a valid JSON string")
except json.decoder.JSONDecodeError:
print("data is not a valid JSON string")
By using a try-except
block, you will be able to catch when the JSON string is invalid.
You still need to find out why an invalid JSON string is passed to the loads()
function, though.
Most likely, you may have a typo somewhere in your JSON string as in the case above.
Note that the value Nathan
is not enclosed in double quotes:
data = '{"name": Nathan}' # ❌ wrong
data = '{"name": "Nathan"}' # ✅ correct
If you see this in your code, then you need to fix the data to conform to the JSON standards.
Another case when this error may happen is when you load an empty .json
file.
Suppose you try to load a file named data.json
file with the following code:
with open("data.json", "r") as file:
data = json.loads(file.read())
If the data.json
file is empty, Python will respond with an error:
Traceback (most recent call last):
File ...
data = json.loads(file.read())
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
The same error also occurs if you have invalid JSON content in the file as follows:
JSON string with invalid format
To avoid this error, you need to make sure that the .json
file you load is not empty and has valid JSON content.
You can use a try-except
block in this case to catch this error:
try:
with open("data.json", "r") as file:
data = json.loads(file.read())
print("file has valid JSON content")
except json.decoder.JSONDecodeError:
print("file is empty or contain invalid JSON")
If you want to validate the source file, you can use jsonlint.com.
When you send an HTTP request using the requests
library, you may use the .json()
method from the response
object to extract the JSON content:
import requests
response = requests.get('https://api.github.com')
data = response.json()
print(data)
But if the response
object doesn’t contain a valid JSON encoding, then a JSONDecodeError
will be raised:
Traceback (most recent call last):
...
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File ...
data = response.json()
requests.exceptions.JSONDecodeError: Expecting value: line 7 column 1 (char 6)
As you can see, the requests
object also has the JSONDecodeError: Expecting value
message.
To resolve this error, you need to surround the call to response.json()
with a try-except
block as follows:
import requests
response = requests.get('https://api.github.com')
try:
data = response.json()
print(data)
except:
print("Error from server: " + str(response.content))
When the except
block is triggered, you will get the response content
printed in a string format.
You need to inspect the print output for more insight as to why the response is not a valid JSON format.
In this article, we have seen how to fix the JSONDecodeError: Expecting value
error when using Python.
This error can happen in three different cases: when you decode invalid JSON content, load an empty or invalid .json file, and make an HTTP request that doesn’t return a valid JSON.
By following the steps in this article, you will be able to debug and fix this error when it occurs.
Until next time, happy coding! 🙌
Original article source at: https://sebhastian.com/
1675267080
This tutorial dives into JavaScript error handling so you’ll be able to throw, detect, and handle your own errors.
Expert developers expect the unexpected. If something can go wrong, it will go wrong — typically, the moment the first user accesses your new web system.
We can avoid some web application errors like so:
Yet errors remain. Browsers may fail or not support an API we’re using. Servers can fail or take too long to respond. Network connectivity can fail or become unreliable. Issues may be temporary, but we can’t code our way around such problems. However, we can anticipate problems, take remedial actions, and make our application more resilient.
Ideally, users should never see error messages.
We may be able to ignore minor issues, such as a decorative image failing to load. We could address more serious problems such as Ajax data-save failures by storing data locally and uploading later. An error only becomes necessary when the user is at risk of losing data — presuming they can do something about it.
It’s therefore necessary to catch errors as they occur and determine the best action. Raising and catching errors in a JavaScript application can be daunting at first, but it’s possibly easier than you expect.
When a JavaScript statement results in an error, it’s said to throw an exception. JavaScript creates and throws an Error
object describing the error. We can see this in action in this CodePen demo. If we set the decimal places to a negative number, we’ll see an error message in the console at the bottom. (Note that we’re not embedding the CodePens in this tutorial, because you need to be able to see the console output for them to make sense.)
The result won’t update, and we’ll see a RangeError
message in the console. The following function throws the error when dp
is negative:
// division calculation
function divide(v1, v2, dp) {
return (v1 / v2).toFixed(dp);
}
After throwing the error, the JavaScript interpreter checks for exception handling code. None is present in the divide()
function, so it checks the calling function:
// show result of division
function showResult() {
result.value = divide(
parseFloat(num1.value),
parseFloat(num2.value),
parseFloat(dp.value)
);
}
The interpreter repeats the process for every function on the call stack until one of these things happens:
We can add an exception handler to the divide()
function with a try…catch block:
// division calculation
function divide(v1, v2, dp) {
try {
return (v1 / v2).toFixed(dp);
}
catch(e) {
console.log(`
error name : ${ e.name }
error message: ${ e.message }
`);
return 'ERROR';
}
}
This executes the code in the try {}
block but, when an exception occurs, the catch {}
block executes and receives the thrown error object. As before, try setting the decimal places to a negative number in this CodePen demo.
The result now shows ERROR. The console shows the error name and message, but this is output by the console.log
statement and doesn’t terminate the program.
Note: this demonstration of a try...catch
block is overkill for a basic function such as divide()
. It’s simpler to ensure dp
is zero or higher, as we’ll see below.
We can define an optional finally {}
block if we require code to run when either the try
or catch
code executes:
function divide(v1, v2, dp) {
try {
return (v1 / v2).toFixed(dp);
}
catch(e) {
return 'ERROR';
}
finally {
console.log('done');
}
}
The console outputs "done"
, whether the calculation succeeds or raises an error. A finally
block typically executes actions which we’d otherwise need to repeat in both the try
and the catch
block — such as cancelling an API call or closing a database connection.
A try
block requires either a catch
block, a finally
block, or both. Note that, when a finally
block contains a return
statement, that value becomes the return value for the whole function; other return
statements in try
or catch
blocks are ignored.
What happens if we add an exception handler to the calling showResult()
function?
// show result of division
function showResult() {
try {
result.value = divide(
parseFloat(num1.value),
parseFloat(num2.value),
parseFloat(dp.value)
);
}
catch(e) {
result.value = 'FAIL!';
}
}
The answer is … nothing! This catch
block is never reached, because the catch
block in the divide()
function handles the error.
However, we could programmatically throw a new Error
object in divide()
and optionally pass the original error in a cause
property of the second argument:
function divide(v1, v2, dp) {
try {
return (v1 / v2).toFixed(dp);
}
catch(e) {
throw new Error('ERROR', { cause: e });
}
}
This will trigger the catch
block in the calling function:
// show result of division
function showResult() {
try {
//...
}
catch(e) {
console.log( e.message ); // ERROR
console.log( e.cause.name ); // RangeError
result.value = 'FAIL!';
}
}
When an exception occurs, JavaScript creates and throws an object describing the error using one of the following types.
An error thrown by syntactically invalid code such as a missing bracket:
if condition) { // SyntaxError
console.log('condition is true');
}
Note: languages such as C++ and Java report syntax errors during compilation. JavaScript is an interpreted language, so syntax errors aren’t identified until the code runs. Any good code editor or linter can spot syntax errors before we attempt to run code.
An error thrown when accessing a non-existent variable:
function inc() {
value++; // ReferenceError
}
Again, good code editors and linters can spot these issues.
An error thrown when a value isn’t of an expected type, such as calling a non-existent object method:
const obj = {};
obj.missingMethod(); // TypeError
An error thrown when a value isn’t in the set or range of allowed values. The toFixed() method used above generates this error, because it expects a value typically between 0 and 100:
const n = 123.456;
console.log( n.toFixed(-1) ); // RangeError
An error thrown by URI-handling functions such as encodeURI() and decodeURI() when they encounter malformed URIs:
const u = decodeURIComponent('%'); // URIError
An error thrown when passing a string containing invalid JavaScript code to the eval() function:
eval('console.logg x;'); // EvalError
Note: please don’t use eval()
! Executing arbitrary code contained in a string possibly constructed from user input is far too dangerous!
An error thrown when several errors are wrapped in a single error. This is typically raised when calling an operation such as Promise.all(), which returns results from any number of promises.
A non-standard (Firefox only) error thrown when an error occurs internally in the JavaScript engine. It’s typically the result of something taking too much memory, such as a large array or “too much recursion”.
Finally, there is a generic Error
object which is most often used when implementing our own exceptions … which we’ll cover next.
We can throw
our own exceptions when an error occurs — or should occur. For example:
The throw
statement actually accepts any value or object. For example:
throw 'A simple error string';
throw 42;
throw true;
throw { message: 'An error', name: 'MyError' };
Exceptions are thrown to every function on the call stack until they’re intercepted by an exception (catch
) handler. More practically, however, we’ll want to create and throw an Error
object so they act identically to standard errors thrown by JavaScript.
We can create a generic Error
object by passing an optional message to the constructor:
throw new Error('An error has occurred');
We can also use Error
like a function without new
. It returns an Error
object identical to that above:
throw Error('An error has occurred');
We can optionally pass a filename and a line number as the second and third parameters:
throw new Error('An error has occurred', 'script.js', 99);
This is rarely necessary, since they default to the file and line where we threw the Error
object. (They’re also difficult to maintain as our files change!)
We can define generic Error
objects, but we should use a standard Error type when possible. For example:
throw new RangeError('Decimal places must be 0 or greater');
All Error
objects have the following properties, which we can examine in a catch
block:
.name
: the name of the Error type — such as Error
or RangeError
.message
: the error messageThe following non-standard properties are also supported in Firefox:
.fileName
: the file where the error occurred.lineNumber
: the line number where the error occurred.columnNumber
: the column number on the line where the error occurred.stack
: a stack trace listing the function calls made before the error occurredWe can change the divide()
function to throw a RangeError
when the number of decimal places isn’t a number, is less than zero, or is greater than eight:
// division calculation
function divide(v1, v2, dp) {
if (isNaN(dp) || dp < 0 || dp > 8) {
throw new RangeError('Decimal places must be between 0 and 8');
}
return (v1 / v2).toFixed(dp);
}
Similarly, we could throw an Error
or TypeError
when the dividend value isn’t a number to prevent NaN
results:
if (isNaN(v1)) {
throw new TypeError('Dividend must be a number');
}
We can also cater for divisors that are non-numeric or zero. JavaScript returns Infinity when dividing by zero, but that could confuse users. Rather than raising a generic Error
, we could create a custom DivByZeroError
error type:
// new DivByZeroError Error type
class DivByZeroError extends Error {
constructor(message) {
super(message);
this.name = 'DivByZeroError';
}
}
Then throw it in the same way:
if (isNaN(v2) || !v2) {
throw new DivByZeroError('Divisor must be a non-zero number');
}
Now add a try...catch
block to the calling showResult()
function. It can receive any Error
type and react accordingly — in this case, showing the error message:
// show result of division
function showResult() {
try {
result.value = divide(
parseFloat(num1.value),
parseFloat(num2.value),
parseFloat(dp.value)
);
errmsg.textContent = '';
}
catch (e) {
result.value = 'ERROR';
errmsg.textContent = e.message;
console.log( e.name );
}
}
Try entering invalid non-numeric, zero, and negative values into this CodePen demo.
The final version of the divide()
function checks all the input values and throws an appropriate Error
when necessary:
// division calculation
function divide(v1, v2, dp) {
if (isNaN(v1)) {
throw new TypeError('Dividend must be a number');
}
if (isNaN(v2) || !v2) {
throw new DivByZeroError('Divisor must be a non-zero number');
}
if (isNaN(dp) || dp < 0 || dp > 8) {
throw new RangeError('Decimal places must be between 0 and 8');
}
return (v1 / v2).toFixed(dp);
}
It’s no longer necessary to place a try...catch
block around the final return
, since it should never generate an error. If one did occur, JavaScript would generate its own error and have it handled by the catch
block in showResult()
.
We can’t catch exceptions thrown by callback-based asynchronous functions, because an error is thrown after the try...catch
block completes execution. This code looks correct, but the catch
block will never execute and the console displays an Uncaught Error
message after one second:
function asyncError(delay = 1000) {
setTimeout(() => {
throw new Error('I am never caught!');
}, delay);
}
try {
asyncError();
}
catch(e) {
console.error('This will never run');
}
The convention presumed in most frameworks and server runtimes such as Node.js is to return an error as the first parameter to a callback function. That won’t raise an exception, although we could manually throw an Error
if necessary:
function asyncError(delay = 1000, callback) {
setTimeout(() => {
callback('This is an error message');
}, delay);
}
asyncError(1000, e => {
if (e) {
throw new Error(`error: ${ e }`);
}
});
Callbacks can become unwieldy, so it’s preferable to use promises when writing asynchronous code. When an error occurs, the promise’s reject()
method can return a new Error
object or any other value:
function wait(delay = 1000) {
return new Promise((resolve, reject) => {
if (isNaN(delay) || delay < 0) {
reject( new TypeError('Invalid delay') );
}
else {
setTimeout(() => {
resolve(`waited ${ delay } ms`);
}, delay);
}
})
}
Note: functions must be either 100% synchronous or 100% asynchronous. This is why it’s necessary to check the delay
value inside the returned promise. If we checked the delay
value and threw an error before returning the promise, the function would become synchronous when an error occurred.
The Promise.catch() method executes when passing an invalid delay
parameter and it receives to the returned Error
object:
// invalid delay value passed
wait('INVALID')
.then( res => console.log( res ))
.catch( e => console.error( e.message ) )
.finally( () => console.log('complete') );
Personally, I find promise chains a little difficult to read. Fortunately, we can use await
to call any function which returns a promise. This must occur inside an async
function, but we can capture errors using a standard try...catch
block.
The following (immediately invoked) async
function is functionally identical to the promise chain above:
(async () => {
try {
console.log( await wait('INVALID') );
}
catch (e) {
console.error( e.message );
}
finally {
console.log('complete');
}
})();
Throwing Error
objects and handling exceptions is easy in JavaScript:
try {
throw new Error('I am an error!');
}
catch (e) {
console.log(`error ${ e.message }`)
}
Building a resilient application that reacts appropriately to errors and makes life easy for users is more challenging. Always expect the unexpected.
Further information:
Original article source at: https://www.sitepoint.com/
1674840840
In this quick tip on PHP error reporting, we’ll look at how to use the tools available in PHP to handle errors in a controlled way and thereby save hours of debugging.
PHP is, by definition, an “exception-light” programming language. This means that, while it does have exceptions, it will continue to execute any script regardless of what happens unless a fatal error occurs.
For example:
<?php
echo $sitepoint;
The code above will return the following message:
Notice: Undefined variable: sitepoint in PHP shell code on line 1
PHP will only throw a notice error, and will happily continue executing. An “exception-heavy” language like Python will throw an error and halt execution.
Because of this behavior, PHP developers must be extra careful when writing their code. Unexpected results in the execution of programs might occur, because notices won’t halt the execution but may impact the correct behavior of the program.
Before we go into how to adjust the error reporting style in PHP, let’s first understand the several levels of PHP error severity.
PHP has three main types of messages: errors, notices, and warnings. These represent the different levels of severity: E_ERROR
, E_NOTICE
, and E_WARNING
.
Errors are fatal runtime errors and are usually caused by faults in the code. This will cause PHP to stop executing.
Notices are messages caused by code that may or may not cause problems (for example, an undefined variable). These will not cause an execution halt.
Warnings are non-fatal errors and the script execution won’t be halted.
By default, PHP doesn’t log any errors. For that to happen, we have to specifically tell it to start logging by turning on the display_errors
variable on the PHP configuration file (the php.ini
file).
In this file, we can additionally tell PHP if we also want to log notices and warnings, and where this log should be recorded.
There’s also the possibility to trigger logging from within the code. To do this, we can use the error_log()
function. Since error logging isn’t the main focus of this article, more information can be found here.
We can change the default PHP error reporting behavior by using the error_reporting()
function. With this function, we can set the level of errors for the duration of the script. This is done by passing one or more of the predefined error constants to the function.
For example, if we want to see not only errors but also notices we could use this:
<?php
error_Reporting(E_ERROR | E_NOTICE);
With this declaration, the script execution will be halted not only for errors but also for notices.
We can also tell PHP to suppress specific errors by using the error control operator (@
). By putting this operator at the beginning of an expression, any error that’s a direct result of that expression is silenced:
<?php
echo @$sitepoint;
This will output the value of $sitepoint
if it exists, but it’s going to return a NULL
and print nothing (instead of throwing a notice) if it doesn’t.
Be very careful when using this operator, as it will completely hide the error. Not only will the error not be displayed, but it also won’t be sent to the error log.
While it may seem harmless, by using this operator you’ll be masking deeper structural issues within your code and covering up potential errant behaviors.
Finally, PHP can also be used as an “exception-heavy” programming language. Normal PHP errors may be thrown as exceptions by using the ErrorException
class that extends the PHP Exception
class.
In the following example, a user-defined function called errorhandler()
is set as error handler with the set_error_handler()
function. It throws an ErrorException
when a fatal error occurs because a file isn’t found with the file_get_contents()
function:
<?php
function errorHandler($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
return;
}
throw new ErrorException("Fatal Error:No such file or directory", 0, E_ERROR);
}
set_error_handler("errorHandler");
try {
$data=file_get_contents("sitepoint.txt");
echo $data;
} catch (ErrorException $e) {
echo $e->getMessage();
}
By using this method, we can handle execution errors the way we handle exceptions, wrapping them in a try…catch
statement with proper instructions on how to behave in such situations.
Summing up, PHP may handle errors in a very loose fashion. It’s up to us developers to use the available tools to better handle them so we can make the most out of the language. By using this set of tools, we can handle errors in a controlled way, saving hours of debugging this way.
Original article source at: https://www.sitepoint.com/
1672904728
Reporting errors to Bugsnag.
Update your Package.swift
file.
.package(url: "https://github.com/nodes-vapor/bugsnag.git", from: "4.0.0")
Update configure.swift
public func configure(_ app: Application) throws {
// Configure Bugsnag.
app.bugsnag.configuration = .init(
apiKey: "<YOUR BUGSNAG API KEY>",
releaseStage: app.environment.name,
shouldReport: app.environment.name != "local"
)
// Add Bugsnag middleware.
app.middleware.use(BugsnagMiddleware())
}
BugsnagMiddleware
will automatically report errors thrown by your route handlers. You can report errors manually from Application
or Request
.
// Reporting from Application.
app.bugsnag.report(Abort(.internalServerError))
// Reporting from Request.
app.get("test") { req in
req.bugsnag.report(Abort(.upgradeRequired))
return HTTPStatus.ok
}
By conforming to the BugsnagError
protocol you can have full control over how your errors are reported. It has the following properties:
Name | Type | Function | Default |
---|---|---|---|
shouldReport | Bool | Opt out of error reporting by returning false | true |
severity | Severity | Indicate error severity (.info |.warning |.error ) | .error |
metadata | [String: CustomDebugStringConvertible] | Additional metadata to include in the report | [:] |
Conforming your Authenticatable
model to BugsnagUser
allows you to easily pair the data to a report.
extension TestUser: BugsnagUser {
var bugsnagID: CustomStringConvertible? {
self.id
}
}
Configure all user models you would like Bugsnag to report.
// Add to configure.swift.
app.bugsnag.users.add(TestUser.self)
Bugsnag will automatically check Vapor's authentication API for the configured user types and report the user's identifier if they are logged in.
Breadcrumbs enable you to attach custom events to your reports. Leave a breadcrumb using the convenience function on Request
.
req.bugsnag.breadcrumb(
name: "Something happened!",
type: .manual,
metadata: ["foo": "bar"]
)
The breadcrumb types are provided by Bugsnag:
enum BugsnagBreadcrumbType {
case error
case log
case manual
case navigation
case process
case request
case state
case user
}
Usually you will receive information such as headers, query params or post body fields in the reports from Bugsnag. To ensure that you do not track sensitive information, you can configure Bugsnag with a list of fields that should be filtered out:
app.bugsnag.configuration = .init(
apiKey: "foo",
releaseStage: "debug",
keyFilters: ["email", "password"]
)
In this case Bugsnag Reports will hide header fields, query params or post body json fields with the keys/names email and password.
⚠️ Note: If key filters are defined and Bugsnag does not know how to parse the request body, the entire body will be hidden.
This package is developed and maintained by the Vapor team at Nodes.
Author: Nodes-vapor
Source Code: https://github.com/nodes-vapor/bugsnag
1671301320
Node.js developers often find themselves working with chaotic code that’s anything but clean. This can obviously cause productivity issues and outright errors. In this article, Toptal Full-stack Developer Jay Huang will introduce you to error-handling in Node.js and demonstrate how you can build a robust error-handling system yourself.
It is not hard to see that some people are struggling to handle errors, and some are even totally missing it. Handling errors properly means not only reducing the development time by finding bugs and errors easily but also developing a robust codebase for large-scale applications.
In particular, Node.js developers sometimes find themselves working with not-so-clean code while handling various kinds of errors, incorrectly applying the same logic everywhere to deal with them. They just keep asking themselves “Is Node.js bad at handling errors?” or If not, how to handle them?” My answer to them is “No, Node.js is not bad at all. That depends on us developers.”
Here is one of my favorite solutions for that.
First of all, it is necessary to have a clear understanding of errors in Node.js. In general, Node.js errors are divided into two distinct categories: operational errors and programmer errors.
With that in mind, you should have no problem distinguishing between these two categories of errors: Operational errors are a natural part of an application, and programmer errors are bugs caused by developers. A logical question that follows is: “Why is it useful to divide them into two categories and deal with them?”
Without a clear understanding of errors, you might feel like restarting an application whenever an error occurs. Does it make sense to restart an application due to “File Not Found” errors when thousands of users are enjoying the application? Absolutely not.
But what about programmer errors? Does it make sense to keep an application running when an unknown bug appears that could result in an unexpected snowball effect in the application? Again, definitely not!
Assuming you have some experience with async JavaScript and Node.js, you might have experienced drawbacks when using callbacks for dealing with errors. They force you to check errors all the way down to nested ones, causing notorious “callback hell” issues that make it hard to follow the code flow.
Using promises or async/await is a good replacement for callbacks. The typical code flow of async/await looks like the following:
const doAsyncJobs = async () => {
try {
const result1 = await job1();
const result2 = await job2(result1);
const result3 = await job3(result2);
return await job4(result3);
} catch (error) {
console.error(error);
} finally {
await anywayDoThisJob();
}
}
Using Node.js built-in Error object is a good practice because it includes intuitive and clear information about errors like StackTrace, which most developers depend on to keep track of the root of an error. And additional meaningful properties like HTTP status code and a description by extending the Error class will make it more informative.
class BaseError extends Error {
public readonly name: string;
public readonly httpCode: HttpStatusCode;
public readonly isOperational: boolean;
constructor(name: string, httpCode: HttpStatusCode, description: string, isOperational: boolean) {
super(description);
Object.setPrototypeOf(this, new.target.prototype);
this.name = name;
this.httpCode = httpCode;
this.isOperational = isOperational;
Error.captureStackTrace(this);
}
}
//free to extend the BaseError
class APIError extends BaseError {
constructor(name, httpCode = HttpStatusCode.INTERNAL_SERVER, isOperational = true, description = 'internal server error') {
super(name, httpCode, isOperational, description);
}
}
I only implemented some HTTP status codes for the sake of simplicity, but you are free to add more later.
export enum HttpStatusCode {
OK = 200,
BAD_REQUEST = 400,
NOT_FOUND = 404,
INTERNAL_SERVER = 500,
}
There is no need to extend BaseError or APIError, but it is okay to extend it for common errors according to your needs and personal preferences.
class HTTP400Error extends BaseError {
constructor(description = 'bad request') {
super('NOT FOUND', HttpStatusCode.BAD_REQUEST, true, description);
}
}
So how do you use it? Just throw this in:
...
const user = await User.getUserById(1);
if (user === null)
throw new APIError(
'NOT FOUND',
HttpStatusCode.NOT_FOUND,
true,
'detailed explanation'
);
Now, we are ready to build the main component of our Node.js error-handling system: the centralized error-handling component.
It is usually a good idea to build a centralized error-handling component in order to avoid possible code duplications when handling errors. The error-handling component is in charge of making the caught errors understandable by, for example, sending notifications to system admins (if necessary), transferring events to a monitoring service like Sentry.io, and logging them.
Here is a basic workflow for dealing with errors:
In some parts of the code, errors are caught to transfer to an error-handling middleware.
...
try {
userService.addNewUser(req.body).then((newUser: User) => {
res.status(200).json(newUser);
}).catch((error: Error) => {
next(error)
});
} catch (error) {
next(error);
}
...
The error-handling middleware is a good place to distinguish between error types and send them to the centralized error-handling component. Knowing the basics about handling errors in Express.js middleware would certainly help.
app.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {
if (!errorHandler.isTrustedError(err)) {
next(err);
}
await errorHandler.handleError(err);
});
By now, one can imagine what the centralized component should look like because we have already used some of its functions. Bear in mind that it is totally up to you how to implement it, but it might look like the following:
class ErrorHandler {
public async handleError(err: Error): Promise<void> {
await logger.error(
'Error message from the centralized error-handling component',
err,
);
await sendMailToAdminIfCritical();
await sendEventsToSentry();
}
public isTrustedError(error: Error) {
if (error instanceof BaseError) {
return error.isOperational;
}
return false;
}
}
export const errorHandler = new ErrorHandler();
Sometimes, the output of the default “console.log” makes it difficult to keep track of errors. Rather, it could be much better to print errors in a formatted way so that developers can quickly understand the issues and make sure they are fixed.
Overall, this will save developers time making it easy to keep track of errors and handle them by increasing their visibility. It is a good decision to employ a customizable logger like winston or morgan.
Here is a customized winston logger:
const customLevels = {
levels: {
trace: 5,
debug: 4,
info: 3,
warn: 2,
error: 1,
fatal: 0,
},
colors: {
trace: 'white',
debug: 'green',
info: 'green',
warn: 'yellow',
error: 'red',
fatal: 'red',
},
};
const formatter = winston.format.combine(
winston.format.colorize(),
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.splat(),
winston.format.printf((info) => {
const { timestamp, level, message, ...meta } = info;
return `${timestamp} [${level}]: ${message} ${
Object.keys(meta).length ? JSON.stringify(meta, null, 2) : ''
}`;
}),
);
class Logger {
private logger: winston.Logger;
constructor() {
const prodTransport = new winston.transports.File({
filename: 'logs/error.log',
level: 'error',
});
const transport = new winston.transports.Console({
format: formatter,
});
this.logger = winston.createLogger({
level: isDevEnvironment() ? 'trace' : 'error',
levels: customLevels.levels,
transports: [isDevEnvironment() ? transport : prodTransport],
});
winston.addColors(customLevels.colors);
}
trace(msg: any, meta?: any) {
this.logger.log('trace', msg, meta);
}
debug(msg: any, meta?: any) {
this.logger.debug(msg, meta);
}
info(msg: any, meta?: any) {
this.logger.info(msg, meta);
}
warn(msg: any, meta?: any) {
this.logger.warn(msg, meta);
}
error(msg: any, meta?: any) {
this.logger.error(msg, meta);
}
fatal(msg: any, meta?: any) {
this.logger.log('fatal', msg, meta);
}
}
export const logger = new Logger();
What it basically provides is logging at multiple different levels in a formatted way, with clear colors, and logging into different output media according to the runtime environment. The good thing with this is you can watch and query logs by using winston’s built-in APIs. Furthermore, you can use a log analysis tool to analyze the formatted log files to get more useful information about the application. It’s awesome, isn’t it?
Up to this point, we mostly discussed dealing with operational errors. How about programmer errors? The best way to deal with these errors is to crash immediately and restart gracefully with an automatic restarter like PM2—the reason being that programmer errors are unexpected, as they are actual bugs that might cause the application to end up in a wrong state and behave in an unexpected way.
process.on('uncaughtException', (error: Error) => {
errorHandler.handleError(error);
if (!errorHandler.isTrustedError(error)) {
process.exit(1);
}
});
Last but not least, I am going to mention dealing with unhandled promise rejections and exceptions.
You might find yourself spending a lot of time dealing with promises when working on Node.js/Express applications. It is not hard to see warning messages about unhandled promise rejections when you forget to handle rejections.
The warning messages don’t do much except logging, but it is a good practice to use a decent fallback and subscribe to process.on(‘unhandledRejection’, callback)
.
The typical error-handling flow might look like the following:
// somewhere in the code
...
User.getUserById(1).then((firstUser) => {
if (firstUser.isSleeping === false) throw new Error('He is not sleeping!');
});
...
// get the unhandled rejection and throw it to another fallback handler we already have.
process.on('unhandledRejection', (reason: Error, promise: Promise<any>) => {
throw reason;
});
process.on('uncaughtException', (error: Error) => {
errorHandler.handleError(error);
if (!errorHandler.isTrustedError(error)) {
process.exit(1);
}
});
When all is said and done, you should realize that error-handling is not an optional extra but rather an essential part of an application, both in the development stage and in production.
The strategy of handling errors in a single component in Node.js will ensure developers save valuable time and write clean and maintainable code by avoiding code duplication and missing error context.
I hope you enjoyed reading this article and found the discussed error-handling workflow and implementation helpful for building a robust codebase in Node.js.
Original article source at: https://www.toptal.com/
1670490000
Maintainable Express.js code after scaling means making common code more feature-rich while reducing boilerplate. Find out how to enable promise-based route code and centralize both error handling and normal-results handling in Express.js apps.
The Express.js tagline rings true: It’s a “fast, unopinionated, minimalist web framework for Node.js.” It’s so unopinionated that, despite current JavaScript best practices prescribing the use of promises, Express.js doesn’t support promise-based route handlers by default.
With many Express.js tutorials leaving out that detail, developers often get in the habit of copying and pasting result-sending and error-handling code for each route, creating technical debt as they go. We can avoid this antipattern (and its fallout) with the technique we’ll cover today—one I’ve used successfully in apps with hundreds of routes.
Let’s start with an Express.js tutorial application with a few routes for a user model.
In real projects, we would store the related data in some database like MongoDB. But for our purposes, data storage specifics are unimportant, so we will mock them out for the sake of simplicity. What we won’t simplify is good project structure, the key to half the success of any project.
Yeoman can yield much better project skeletons in general, but for what we need, we’ll simply create a project skeleton with express-generator and remove the unnecessary parts, until we have this:
bin
start.js
node_modules
routes
users.js
services
userService.js
app.js
package-lock.json
package.json
We’ve pared down the lines of the remaining files that aren’t related to our goals.
Here’s the main Express.js application file, ./app.js
:
const createError = require('http-errors');
const express = require('express');
const cookieParser = require('cookie-parser');
const usersRouter = require('./routes/users');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use('/users', usersRouter);
app.use(function(req, res, next) {
next(createError(404));
});
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.send(err);
});
module.exports = app;
Here we create an Express.js app and add some basic middleware to support JSON use, URL encoding, and cookie parsing. We then add a usersRouter
for /users
. Finally, we specify what to do if no route is found, and how to handle errors, which we will change later.
The script to start the server itself is /bin/start.js
:
const app = require('../app');
const http = require('http');
const port = process.env.PORT || '3000';
const server = http.createServer(app);
server.listen(port);
Our /package.json
is also barebones:
{
"name": "express-promises-example",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/start.js"
},
"dependencies": {
"cookie-parser": "~1.4.4",
"express": "~4.16.1",
"http-errors": "~1.6.3"
}
}
Let’s use a typical user router implementation in /routes/users.js
:
const express = require('express');
const router = express.Router();
const userService = require('../services/userService');
router.get('/', function(req, res) {
userService.getAll()
.then(result => res.status(200).send(result))
.catch(err => res.status(500).send(err));
});
router.get('/:id', function(req, res) {
userService.getById(req.params.id)
.then(result => res.status(200).send(result))
.catch(err => res.status(500).send(err));
});
module.exports = router;
It has two routes: /
to get all users and /:id
to get a single user by ID. It also uses /services/userService.js
, which has promise-based methods to get this data:
const users = [
{id: '1', fullName: 'User The First'},
{id: '2', fullName: 'User The Second'}
];
const getAll = () => Promise.resolve(users);
const getById = (id) => Promise.resolve(users.find(u => u.id == id));
module.exports = {
getById,
getAll
};
Here we’ve avoided using an actual DB connector or ORM (e.g., Mongoose or Sequelize), simply mimicking data fetching with Promise.resolve(...)
.
Looking at our route handlers, we see that each service call uses duplicate .then(...)
and .catch(...)
callbacks to send data or errors back to the client.
At first glance, this may not seem serious. Let’s add some basic real-world requirements: We’ll need to display only certain errors and omit generic 500-level errors; also, whether we apply this logic or not must be based on the environment. With that, what will it look like when our example project grows from its two routes into a real project with 200 routes?
Maybe we would create separate utility functions to handle resolve
and reject
, and apply them everywhere in our Express.js routes:
// some response handlers in /utils
const handleResponse = (res, data) => res.status(200).send(data);
const handleError = (res, err) => res.status(500).send(err);
// routes/users.js
router.get('/', function(req, res) {
userService.getAll()
.then(data => handleResponse(res, data))
.catch(err => handleError(res, err));
});
router.get('/:id', function(req, res) {
userService.getById(req.params.id)
.then(data => handleResponse(res, data))
.catch(err => handleError(res, err));
});
Looks better: We’re not repeating our implementation of sending data and errors. But we’ll still need to import these handlers in every route and add them to each promise passed to then()
and catch()
.
Another solution could be to use Express.js best practices around promises: Move error-sending logic into Express.js error middleware (added in app.js
) and pass async errors to it using the next
callback. Our basic error middleware setup would use a simple anonymous function:
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.send(err);
});
Express.js understands that this is for errors because the function signature has four input arguments. (It leverages the fact that every function object has a .length
property describing how many parameters the function expects.)
Passing errors via next
would look like this:
// some response handlers in /utils
const handleResponse = (res, data) => res.status(200).send(data);
// routes/users.js
router.get('/', function(req, res, next) {
userService.getAll()
.then(data => handleResponse(res, data))
.catch(next);
});
router.get('/:id', function(req, res, next) {
userService.getById(req.params.id)
.then(data => handleResponse(res, data))
.catch(next);
});
Even using the official best practice guide, we still need our JS promises in every route handler to resolve using a handleResponse()
function and reject by passing along the next
function.
Let’s try to simplify that with a better approach.
One of the greatest features of JavaScript is its dynamic nature. We can add any field to any object at runtime. We’ll use that to extend Express.js result objects; Express.js middleware functions are a convenient place to do so.
promiseMiddleware()
FunctionLet’s create our promise middleware, which will give us the flexibility to structure our Express.js routes more elegantly. We’ll need a new file, /middleware/promise.js
:
const handleResponse = (res, data) => res.status(200).send(data);
const handleError = (res, err = {}) => res.status(err.status || 500).send({error: err.message});
module.exports = function promiseMiddleware() {
return (req,res,next) => {
res.promise = (p) => {
let promiseToResolve;
if (p.then && p.catch) {
promiseToResolve = p;
} else if (typeof p === 'function') {
promiseToResolve = Promise.resolve().then(() => p());
} else {
promiseToResolve = Promise.resolve(p);
}
return promiseToResolve
.then((data) => handleResponse(res, data))
.catch((e) => handleError(res, e));
};
return next();
};
}
In app.js
, let’s apply our middleware to the overall Express.js app
object and update the default error behavior:
const promiseMiddleware = require('./middlewares/promise');
//...
app.use(promiseMiddleware());
//...
app.use(function(req, res, next) {
res.promise(Promise.reject(createError(404)));
});
app.use(function(err, req, res, next) {
res.promise(Promise.reject(err));
});
Note that we do not omit our error middleware. It’s still an important error handler for all synchronous errors that may exist in our code. But instead of repeating error-sending logic, the error middleware now passes any synchronous errors to the same central handleError()
function via a Promise.reject()
call sent to res.promise()
.
This helps us handle synchronous errors like this one:
router.get('/someRoute', function(req, res){
throw new Error('This is synchronous error!');
});
Finally, let’s use our new res.promise()
in /routes/users.js
:
const express = require('express');
const router = express.Router();
const userService = require('../services/userService');
router.get('/', function(req, res) {
res.promise(userService.getAll());
});
router.get('/:id', function(req, res) {
res.promise(() => userService.getById(req.params.id));
});
module.exports = router;
Note the different uses of .promise()
: We can pass it a function or a promise. Passing functions can help you with methods that don’t have promises; .promise()
sees that it’s a function and wraps it in a promise.
Where is it better to actually send errors to the client? It’s a good code-organization question. We could do that in our error middleware (because it’s supposed to work with errors) or in our promise middleware (because it already has interactions with our response object). I decided to keep all response operations in one place in our promise middleware, but it’s up to each developer to organize their own code.
res.promise()
Is OptionalWe’ve added res.promise()
, but we’re not locked into using it: We’re free to operate with the response object directly when we need to. Let’s look at two cases where this would be useful: redirecting and stream piping.
Suppose we want to redirect users to another URL. Let’s add a function getUserProfilePicUrl()
in userService.js
:
const getUserProfilePicUrl = (id) => Promise.resolve(`/img/${id}`);
And now let’s use it in our users router in async
/await
style with direct response manipulation:
router.get('/:id/profilePic', async function (req, res) {
try {
const url = await userService.getUserProfilePicUrl(req.params.id);
res.redirect(url);
} catch (e) {
res.promise(Promise.reject(e));
}
});
Note how we use async
/await
, perform the redirection, and (most importantly) still have one central place to pass any error because we used res.promise()
for error handling.
Like our profile picture route, piping a stream is another situation where we need to manipulate the response object directly.
To handle requests to the URL we’re now redirecting to, let’s add a route that returns some generic picture.
First we should add profilePic.jpg
in a new /assets/img
subfolder. (In a real project we would use cloud storage like AWS S3, but the piping mechanism would be the same.)
Let’s pipe this image in response to /img/profilePic/:id
requests. We need to create a new router for that in /routes/img.js
:
const express = require('express');
const router = express.Router();
const fs = require('fs');
const path = require('path');
router.get('/:id', function(req, res) {
/* Note that we create a path to the file based on the current working
* directory, not the router file location.
*/
const fileStream = fs.createReadStream(
path.join(process.cwd(), './assets/img/profilePic.png')
);
fileStream.pipe(res);
});
module.exports = router;
Then we add our new /img
router in app.js
:
app.use('/users', require('./routes/users'));
app.use('/img', require('./routes/img'));
One difference likely stands out compared to the redirect case: We haven’t used res.promise()
in the /img
router! This is because the behavior of an already-piped response object being passed an error will be different than if the error occurs in the middle of the stream.
Express.js developers need to pay attention when working with streams in Express.js applications, handling errors differently depending on when they occur. We need to handle errors before piping (res.promise()
can help us there) as well as midstream (based on the .on('error')
handler), but further details are beyond the scope of this article.
res.promise()
As with calling res.promise()
, we’re not locked into implementing it the way we have either. promiseMiddleware.js
can be augmented to accept some options in res.promise()
to allow callers to specify response status codes, content type, or anything else a project might require. It’s up to developers to shape their tools and organize their code so that it best suits their needs.
The approach presented here allows for more elegant route handlers than we started with and a single point of processing results and errors—even those fired outside of res.promise(...)
—thanks to error handling in app.js
. Still, we are not forced to use it and can process edge cases as we want.
The full code from these examples is available on GitHub. From there, developers can add custom logic as needed to the handleResponse()
function, such as changing the response status to 204 instead of 200 if no data is available.
However, the added control over errors is much more useful. This approach helped me concisely implement these features in production:
{error: {message}}
dev
(or test
, etc.), populate the error.stack
fieldThis Express.js route logic was all in one place, without touching any service—a decoupling that left the code much easier to maintain and extend. This is how simple—but elegant—solutions can drastically improve project structure.
Original article source at: https://www.toptal.com/
1669907907
I’m going to walk you through the process of writing error handling in Micronaut which is a very simple, but powerful way, to manage errors.
Error handling is important because it allows you to gracefully handle unexpected errors in your code. By providing custom error handling, you can provide a better user experience by providing more informative error messages and by directing the user to the appropriate resources for help. Additionally, proper error handling can help prevent your code from crashing or behaving unexpectedly.
When we talk about Exception Handling, there are two primary types of errors that we need to consider: checked and unchecked. Checked exceptions are those that the compiler forces you to deal with, whereas unchecked exceptions are not. In order to write error handling in Micronaut, you will need to use try/catch blocks for both types of errors.
Checked exceptions occur at compile time, such as when you try to reference a non-existent file. To handle these, you must wrap your code in a try block and catch the specific exception type that could be thrown. For example:
try {
// Code which may throw a checked exception
} catch (IOException e) {
// Handle the exception here
}
Unchecked exceptions are those which occur at runtime, such as when you try to divide by zero. These do not need to be caught by a try/catch block but can be if you want to handle them specifically. However, it is generally good practice to let these propagate up the call stack so that they can be dealt with at a higher level. For example:
// Code which may throw an unchecked exception
int result = 10 / 0; // Throws an ArithmeticException
When you are writing code in Micronaut, it is important to be aware of how to handle exceptions. This is especially true when you are working with data sources, such as databases or web services.
There are two main ways to handle exceptions in Micronaut: try/catch blocks and error-handling interceptors.
Try/catch blocks are the most common way to handle exceptions in Java code. You can use them to wrap code that might throw an exception and handle the exception if it does occur. For example:
try {
// Code that might throw an exception
} catch (Exception e) {
// Handle the exception
}
Error handling interceptors are a special type of interceptor that are invoked when an exception is thrown. They can be used to do things like log the exception or send an email notification about the error. To use an error handling interceptor, you need to add it to your Micronaut configuration file:
micronaut:
interceptors:
- class: com.example.myapp.interceptors.MyErrorHandlingInterceptor
The Error class is the base class for all errors in Micronaut. It provides the following methods:
The Exception class is the base class for all exceptions in Micronaut. It provides common functionality for all exceptions, such as storing a stack trace.
In conclusion, error handling in Micronaut is a crucial aspect of developing applications with this framework. By understanding how to properly handle errors, you can ensure that your application will be able to gracefully recover from any unexpected situations. With the tips and techniques in this article, you should now be well-equipped to tackle error handling in your own Micronaut applications.
HAPPY LEARNING!
Original article source at: https://blog.knoldus.com/
1669812780
An error caused by calling a non-existent function will cause JavaScript to throw an undefined
error and stop running your code. To prevent the error, you can first check if a function exists in your current JavaScript environment by using a combination of an if
statement and the typeof
operator on the function you want to call.
Only when the typeof
returns "function"
will you call that function to execute it. Let’s look at the following example:
function printMessage(){
console.log("Hello World!");
}
if(typeof printMessage === "function"){
printMessage();
}
When the type of printMessage
is anything other than "function"
, you don’t call the function.
Alternatively, you can also use a try..catch
block to handle the error when a non-existent function is called:
try {
printMessage();
} catch (err) {
console.log(err); // Error: "printMessage is not defined"
}
// code below won't be executed without try..catch block
console.log("abc...");
console.log("...The script execution continues...");
console.log("...even when there's an error");
Without the try..catch
block, the console logs above won’t be executed by JavaScript. You can use the techniques above to check if a JavaScript function exists before calling it.
Original article source at: https://sebhastian.com/
1669699742
When booting your Android phone back, you may see a message that says Encryption unsuccessful on the screen.
Android Encryption unsuccessful
The full message is as follows:
Encryption was interrupted and can’t be completed. As a result, the data on your phone is no longer accessible.
To resume using your phone, you must perform a factory reset. When you set up your phone after the reset, you’ll have an opportunity to restore any data that was backed up to your Google Account.
Encryption is the process of converting information or data into code. It’s used to conceal your personal information and prevent unauthorized access.
When you boot your phone for the first time, Android will ask you to insert the password or PIN to unlock the screen.
Inserting the password or PIN is the trigger that decrypts your data into a readable format by Android.
This error happens when your Android phone is unable to encrypt the data. Instead of accessing the data as it is, Android will respond with the error above.
The cause for the error is hard to pinpoint. It can be caused by your phone’s hardware malfunctioning.
Whatever the cause, you need to remove all data from the phone’s memory to resolve the issue.
To fix the error, you need to tap the Reset Phone button at the bottom of the screen:
Android Encryption unsuccessful fix
Your Android phone will begin the process of resetting your phone to its factory setting. This may take several minutes to complete.
Once done, your Android phone will reboot. You need to set up the phone as if you’re using a brand new phone.
If you still see the error message after rebooting, try to wipe the data yourself from the Android recovery mode.
To enter the recovery mode, you need to perform the following steps:
Here’s an example of performing a factory reset on a Samsung Galaxy phone:
Even if you have a different phone model, the way to enter the recovery mode should be the same.
When you can’t enter the recovery mode, try typing [phone model] recovery mode
into the YouTube search bar to see the one for your model.
Once you wipe data and reboot the phone, you should be able to set up the phone.
If you still see the error message after resetting, then it’s possible that your phone’s internal memory storage (EMMC) is not working.
You need to get the phone to the manufacturer’s customer service and ask if they can help you fix the phone.
I hope this tutorial has been helpful for you. 🙏
Original article source at: https://sebhastian.com/
1669609157
When building your Android application, you might find an error saying that the package android.support.annotation
does not exist.
Here’s an example of the error:
error: package android.support.annotation does not exist
error: cannot find symbol class NonNull
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
Usually, the error above happens when you migrate your Android application to use androidx
libraries.
androidx
is the namespace used by Android Jetpack libraries. It’s a group of Android support libraries that help you in developing an Android application.
The androidx
packages fully replace the android.support
packages, and new features will be added to androidx
.
When you use androidx
, you need to update your Android source code and replace all import
statements for android.support.annotation
package with androidx.annotation
package.
Here’s an example of replacing the import
statement that uses FloatRange
annotation:
// import android.support.annotation.FloatRange;
import androidx.annotation.FloatRange;
public class Color {
@FloatRange(from=0.0,to=1.0)
public float makeOpaque() {
return (float) 0.5;
}
}
Instead of replacing the import
lines one by one, you can try to use the Android Studio’s AndroidX migration feature to help you automate the process.
Before you migrate to AndroidX, please update your annotation library dependencies to version 28.0
first:
dependencies {
implementation 'com.android.support:support-annotations:28.0.0'
}
This is required because AndroidX version 1.0.0
is equivalent to support library version 28.0.0
.
If you use lesser support library versions, other errors may occur when building your application after migration.
To start the migration, add the following two lines to your gradle.properties
file:
android.useAndroidX=true
android.enableJetifier=true
Next, select Refactor > Migrate to AndroidX from your Android Studio top menu.
Once you complete the review and let Android Studio do the refactor, the required androidx
dependencies should be added to your build.gradle
file.
You should also see the import
lines being replaced with the new ones.
If you still see the build error after migrating to AndroidX, then you need to replace the import
statements manually.
Right-click on your application package to open the context menu, then select the Replace in Files… menu as shown below:
Android Studio replace in files menu
In the pop-up window, aim to replace android.support.annotation
with androidx.annotation
for all of your files.
The following screenshot should help:
Replacing Android annotation imports
Click Replace if you want to review the refactor one by one, or click on Replace All to refactor all occurrences at once.
The issue with the annotations library should now be resolved.
If you’re building an Android application using React Native, then you need to also run the jetifier
package after doing all of the steps above.
Note: You need to migrate the React Native Android application using Android Studio by opening the android/
folder in Android Studio.
When you migrate your native Java code using Android Studio, the React Native modules in the node_modules
folder may still contain code that uses the Android support library.
The jetifier
module refactors Java code included in your React Native application to use androidx
instead of android.support
namespaces.
After migrating to AndroidX using Android Studio, run the following steps with NPM:
npm install --save-dev jetifier
npx jetify
Or if you use Yarn:
yarn add jetifier
yarn jetify
The import
statements in your node_modules
folder that uses old Android support libraries will be replaced with androidx
.
Once done, you should be able to run your React Native app:
npx react-native run-android
You might also want to include the call to jetify
in your postinstall
script:
"scripts": {
"postinstall": "jetify"
}
When you update your Node module dependencies with npm install
or npm update
, you need to run the jetify
command again.
Adding jetify
as the postinstall
command will let Node automatically run it after installation.
Now you’ve learned how to fix the android.support.annotation
package does not exist error in your Android application.
Thanks for reading! I hope this tutorial has been useful for you. 🙏
Original article source at: https://sebhastian.com/
1669370291
Sometimes you will encounter an unexpected token error in JavaScript as follows:
let val+ = "Hello";
//Error: Unexpected token '+'
In the code above, the unexpected token error happens because the plus symbol +
is reserved in JavaScript for concatenation and adding two numbers together. It can’t be used for naming variables, so JavaScript throws the unexpected token error.
As you write your JavaScript application, the unexpected token error always occurs because JavaScript expected a specific syntax that’s not fulfilled by your current code. You can generally fix the error by removing or adding a specific JavaScript language symbol to your code.
In another example, the following function
code lacks the closing round bracket )
after the parameter num
:
function square(num {
return num * num;
}
But when you run the code, it says Error: Unexpected token '{'
because JavaScript expects the parenthesis to be closed.
function square(num) {
return num * num;
}
When you’re using a code editor like VSCode, you may notice the syntax color difference between the correct and the wrong code as follows:
JavaScript unexpected token causes wrong syntax color in VSCode
As you can see from the screenshot above, the correct code will color the return
letter purple, but the wrong code simply doesn’t do that.
The cause for unexpected token error for your code may be different, so you need to understand basic JavaScript rules and figure out the right solution yourself.
You could have extra brackets somewhere, like in the following code:
// Unexpected token ')'
for (i = 0; i < 10; i++))
{
console.log(i);
}
Or you may miss a semicolon symbol ;
somewhere as in the code below:
// Unexpected identifier
for (i = 0 i < 10; i++)
{
console.log(i);
}
Whatever the case is, you need to trace the error message and see which line causes you the problem, and you have to apply the right fix yourself.
Original article source at: https://sebhastian.com/
1669343423
When you create a ListActivity
class to host a ListView
object, Android may complain about the lack of the id
attribute for that ListView
.
For example, suppose you have a MainActivity
class as follows:
public class MainActivity extends ListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Then, you create the following activity_main.xml
layout:
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/list" >
</ListView>
When you build and run the Android application, a RuntimeException
error will occur with the following message:
E/AndroidRuntime: FATAL EXCEPTION: main
# ...
Caused by: java.lang.RuntimeException:
Your content must have a ListView whose id attribute is 'android.R.id.list'
at #...
The exception above happens because the ListActivity
class specifically requires a ListView
object that has an id
attribute of @android:id/list
.
The value @+id/list
resolves to R.id.list
while @android:id/list
resolves to android.R.id.list
.
To resolve the error, you need to change the android:id
attribute in your ListView
widget as shown below:
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@android:id/list" >
</ListView>
Rebuild your application and run it again. This time, the error should disappear.
Also, please note that the ListActivity
class has been deprecated in API level 30 (Android 11)
When you need to display a UI component with a list of items, you are recommended to use either ListFragment
or RecyclerView
instead.
Now you’ve learned how to resolve the missing android.R.id.list
id attribute in ListActivity
class. Good work! 👍
Original article source at: https://sebhastian.com/
1669103762
Learn how you can Solve PHP Fatal Error: Unsupported operand types.
The PHP Fatal Error: Unsupported operand types is an error message that indicates you have used operators on values that are not supported.
PHP operators like +
and -
can be used on int
type values. When you try to combine values like array or string with an int
, the error message will appear:
// 👇 unsupported operand types: string + int
print "Hello" + 29;
This fatal error commonly occurs in PHP v8, where the execution of operands is made stricter.
In PHP v7 or below, the string will be ignored and PHP will print out the int
value:
// 👇 php v7 or below
print "Hello" + 29; // 29
To solve this fatal error, you need to make sure that the operands (the values on the left or right side of the operator) are supported by PHP.
Arithmetic operators like +
, -
, *
, and /
support int
and float
types.
You can’t add an array
and an int
, or a string
and a float
when using these operators:
<?php
$arr = [
"name" => "Orange",
"price" => 5,
];
// 👇 unsupported operands: array + int
$arr + 8;
Even PHP v5 will show “Unsupported operand types” when you add an array
and an int
as in the example above.
When you don’t know how to fix the issue, use var_dump()
to see the type of the variable like this:
<?php
$arr = [
"name" => "Orange",
"price" => 5,
];
var_dump($arr);
The above example will output the content of the $arr
variable:
array(2) {
["name"]=>
string(6) "Orange"
["price"]=>
int(5)
}
Knowing that it’s an array, you can choose to perform addition to the number element, which is the price
element:
<?php
$arr = [
"name" => "Orange",
"price" => 5,
];
// 👇 add to the price element
$arr['price'] += 8;
print $arr['price']; // 13
PHP requires you to use supported operand types for the code.
When you see the message “Fatal Error: Unsupported operand types”, you need to pay attention to the variables used as operands.
They are the variables on the left or right side of the operator symbol. You can find information about them using the var_dump()
function.
Once you know the operand types, adjust your code accordingly to solve this error.
And that’s how you handle PHP Fatal Error: Unsupported operand types. Nice work! 😉
Original article source at: https://sebhastian.com/