Building an Error Formatting Utility Library
Now that we have our registration process working properly, now let's see how we can add some more helpful error handling into our application.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

So we already have an error handler in place for our login process. If a user types in a pairing of a email address and a password that doesn't match, then it simply tells them that they typed in the wrong login. That's pretty standard and we don't really need to change that one. However, we do need to add some more detailed type of error handling for our registration process. So a great example of this is you wouldn't want to have, in your application, two users to be able to use the same email address. That would create all kinds of confusion and some security vulnerabilities obviously. So we block against that and in fact, you wouldn't be able to do it.

So what we're going to be implementing isn't blocking that type of behavior because the server is in charge of that. What we're going to be doing is letting the user know when they've typed something wrong. So say they've tried to use an email address that's already in the system, we want to show that to them. We don't want to just have this generic error that says hey, there was a problem creating the account, we want to say hey, there is a problem creating the account because that email address is already in the system. Something like that. Now, the server's already handling that for us. It not only is blocking the user records from being created, it also passes back some very helpful messages whenever that occurs.

So let's test that out right now. So if you have everything up and running, if you open up the simulator and then also the terminal, then let's see what happens here. So I'm going to come in, I'm going to click on Register and I'm going to type in an email address that's already in the system. So reactnative@devcamp.com and I'm going to try to create this account.

If I hit Register here, it gives me our generic alert but if you see the data that was passed back here, you can see that we actually get an error object returned from the server and it says that there's an error and that there's an email address that has already been taken.

large

So this is really helpful. But we can't just print this out. We can't take this object that got passed on and print it out. Instead, what we have to do is we have to actually parse through this response in order to render that to the user. So the end goal here, what we're going to be creating is a JavaScript function that can pull out each of the error elements because we also have to be prepared for other errors. There might be an issue with the password. Depending on the type of application you're building, you could have all kinds of different validations in place. You could have a password that has requirements such as having to have a number or a character or to be a certain length. There's all kinds of things that could be sent back so we need to be able to iterate through all of those elements and print those out to the user.

We also are going to be doing this on a few other parts of the application. So when we get into creating these posts, we also need to provide errors if a user has typed something in that isn't right. So we're going to create a function that can be used throughout the entire application.

So in this guide, that's what we're going to be doing and so what we're going to be creating here is not specific at all to React Native, this is going to be pure JavaScript. And this is really going to be helpful and the reason why I like this guide for you is because you are literally going to be able to take the code that we write here and you're going to be able to copy and paste this into many of your other applications that you're building, whether they be web based or mobile.

So let's get started here. I'm eventually going to create a utility library for all of these kinds of helper functions but for right now, let's just come all the way up to the top and let's create this function. So I'm going to create a fat arrow function and I'm going to call it formatErrors. Just like that. And it's going to take in the error list. So for right now, we don't know what that error list really looks like so I'm just going to say errorList with a type of any and that's going to be a fat arrow function.

AuthScreen.tsx

const formatErrors = (errorList: any) => {

};

So now with that in place, let's first, and one thing that I do a lot of times is I will, when I have some data that I printed out, I'll just copy that and I'll put it up here as a comment. So let me comment all of this out. And so that way, I don't have to keep switching back and forth between the terminal.

large

So with formatErrors, we know we're going to be getting an error list. So we're going to be getting this set of errors right here and so that's the first thing we know that we're going to be receiving. So we need to be able to parse through that. So how do we do that? So inside of here, you could also pretend, if you want, just because sometimes it's helpful when you're looking at an array to have more than one element, you could say that okay, we have the email which could have any number of errors. It could say has already been taken. It could also say something like isn't an actual email address, et cetera. So this is going to be up to the server. We just know that there could be any number of errors for the email. And then the same thing for the password. It wouldn't say has already been taken, but you could say something like needs to be at least six characters. None of that's going to be shown in this. This is just so you have an idea of what that structure's going to look like.

large

So the first thing we need to do is we're getting this errors and even though it kinda looks like an array, because we have multiple items, it's really, as you can see, just an object. So how do you iterate through an object in JavaScript? Well, we use the object class here. So down here, I'm going to call object or I'm first going to store this in a variable. So here I'm just going to say this is our errorContent and then I'm going to say Object dot, so whenever you're wanting to loop through the keys in an object, what you can say is Object.keys. And then you can pass in an object. So in this case, we're passing in that errorList.

AuthScreen.tsx

const formatErrors = (errorList: any) => {
    const errorContent = Object.keys(errorList).map()
};

So we have that errorList and then from there, we're going to map through it. So I'm mapping through it, so I'm looping over each one of the keys. So the way this works is we're passing in errorList which is going to be this or I'm sorry, it's passing in the full error object. So it's going to be passing in the email and those password arrays. So because of that, we have this errorList, when we say Object.keys, that's turning this, what we have this here, this errors: Object, it's almost like we're turning it into an array.

large

Just like that and that's how you are able to loop through these key elements. So here, inside of map, I'm going to say that I'm grabbing the key and then I'm going to inside of here, I have to grab and wrap up an object. So I'm going to put parens here because I want to return this. You could also write this code inside of brackets. Make sure you end that paren. But then you just have to make sure to type return so that's just pure vanilla JavaScript. Whenever you're using map or one of these iterators, if you decide to use a fat arrow function and then you use brackets, then you have to make sure to return. If you write the code like this, then you don't have to do that. If you use parens, it's what's called an implicit return so you don't have to type return.

So inside of there, we want to return an object, so I'm going to use curly brackets here and I'm going to return an object that has the key and then it has the value. And the value is going to be this errorList and then we're going to simply parse the key. So don't worry if this is a little bit tricky. We're going to go through, after we get this working, I'm going to walk through it once again so that you can see everything that's working. This is kinda getting us back to some pure vanilla JavaScript and taking us back to some of the fundamentals, which is always a good thing to do. So I'm going to hit Save.

AuthScreen.tsx

const formatErrors = (errorList: any) => {
  const errorContent = Object.keys(errorList).map(key => ({
    key: key,
    value: errorList[key]
  }));
};

Make sure that we don't have any types of errors there and it looks like we're all good and so now that we have our errorContent, next, we're going to create a formatting system. So here, I'm going to give us a little bit more room and come down here and create a variable. I'm going to say const and I'll say formattedErrors. And then I want to also define what this formattedErrors looks like so because we're using TypeScript, we might as well. So I'm going to say formattedErrors and this is going to be of a type Array which means that we are going to be, we know we're going to be taking in this array and inside of the array, I'm just going to say any because we're not going to dive into each one of those elements and then I'm going to say that this is equal to errorContent and then I'm going to start mapping through that. So we know we're going to get an array of each of these elements and I'm going to do the same thing. So I'm going to say name fat arrow function and in this case, I'm also going to do the explicit return so that you can see both of these side by side. So I'll say return and I'm going to be using string interpolation with the back ticks and so the first thing I'm going to return is the name and then and actually, I want to do the name.key and then from there, a colon, and this is just the formatting side. You could do anything that you want right here. I'm going to add another string interpolation and I'm going to say name.value, because we're looping over this object, and then I'm just going to say join and then a comma and inside of that join.

AuthScreen.tsx

  const formattedErrors: Array<any> = errorContent.map(name => {
    return `${name.key}: ${name.value.join(", ")}`;
  });

So what's going on right here? Well, we are taking in, we're looping over the errorContent. We're going to turn this into an array and so we're looping over the errorContent because we know that this is an array and we're saying I want to grab the name, which in this case would be the first time through is going to be email. Next time through might be password, if that exists. And then I'm grabbing the key, which in this case is email, and then the value. Now, this is something that is just JavaScript, once again. So because we're looping over this element, we have a key and a value. Now, I also use the key shorthand syntax or the object shorthand syntax, if you're curious. So this also could be key: key but because the name is actually the same, we don't have to do that. So we have the key.

So we're grabbing that and then next thing is we're grabbing the value. Now, the value, as you can see is an array because we don't know how many errors are going to be there so I'm grabbing the value and I'm calling join on that array and I'm passing in a comma right afterwards. So the way this would work is when that array, when that value comes in, instead of it being an array, because we can't actually do anything with an array, I'll add this as a comment, what it does is it's taking each of those array elements and it's saying okay, now I'm turning this into one string. So this is now going to just be one string and the first element's going to be has already been taken. Then I'm adding a comma, that's what's happening right here. And then I'm pulling in the next one. And just iterating over that. Once again, this is just vanilla JavaScript and so it definitely good to review it because it doesn't matter how long you do this for, that will get rusty if you're not doing it on a regular basis.

large

And then the last thing we're going to do, because as we can see here, this is returning an array. We can't print out an array here. This has to be a string. So here I'm just going to say return formattedErrors and once again, call join and then just print out that list. So let's hit Save and let's see if this is working.

AuthScreen.tsx

  return formattedErrors.join(", ");

So I'm going to come up to formatErrors, I'm going to grab that and let's come down to our registration here. And instead of saying error creating user account, I'm going to use string interpolation here. And I'll just say error, let's just shorten it, I'll just say error creating account, semicolon and then let's say our formatErrors and pass in response.data.errors. And if you're wondering how you would know about that, once again, that's going to be in your API documentation.

AuthScreen.tsx

          alert(
            `Error creating account: ${formatErrors(response.data.errors)}`
          );

Hit Save and let's test this out. I'm going to hit Refresh just to make sure we're working with the right version of the code. Switch to register and now let's type this in. So reactnative@devcamp.com. Hit Register and there you go. That's working perfect. It says error creating account. The email has already been taken. If there was issue with the password, this would also just, it would add a comma here and then it would show the password. And it would show each one of the errors. So the reason why we're doing this is because we don't know what the data's going to be like. So whenever that's the case, we have to get a little creative with how we're going to format that content and that's what we're doing right here and it looks really good. So I know that might be a little bit tricky. That's getting into more advanced JavaScript. Each one of those things is not trivial to add.

So let's walk through it again but now, let's turn this into a utility function and then we'll dive into what the code's doing. So the way we can do that, I'm going to get rid of all of this debugging content here and I'm going to open up the file system and come down to our utils, this utility directory. I'm going to create a new file here and let's just call this our textFormatters.ts. Not tsx, just .ts so this is just a plain vanilla TypeScript file. I'll close that and now, let's grab formatErrors and remove all of that. And paste it in here. Now, because we need to be able to have access to this, we need to say not expo, export const formatErrors. And remember, that's necessary because whenever you're creating these types of helper functions, you need to be able to import them in different parts of the application. So this is called formatError and it's in textFormatters file. So this is how you can create these utility functions without having to have each one in a dedicated file. So we could add, as we go through the course, we could add any number of functions here to help with formatting and we can call those from anywhere else in the application.

textFormatters.ts

export const formatErrors = (errorList: any) => {
  const errorContent = Object.keys(errorList).map(key => ({
    key: key,
    value: errorList[key]
  }));

  const formattedErrors: Array<any> = errorContent.map(name => {
    return `${name.key}: ${name.value.join(", ")}`;
  });

  return formattedErrors.join(", ");
};

So back in our AuthScreen, let's import this now. So I'm going to say import and now I have to use curly brackets because we didn't do export default, we did just export. So we have to say that I want to import formatErrors and then this is going to be from ../../utils/textFormatters.

AuthScreen.tsx

import { formatErrors } from "../../utils/textFormatters";

There you go and now let's clean that up. Hit Save. We do not have to make any changes down here because we're simply calling this function and we're calling it from that import. So let's just verify it's working. So switching over, reactnative@devcamp.com. And let's try to create to this. Oops, it's not working. Let's add a little change here to make sure that the regular system we had is working. So reactnativenew. Hit Register, everything there is working perfectly.

Okay, perfect. Before we end this guide, let's walk through it one more time. So we are exporting this new utility function that's going to formatErrors. It takes in an errorList, which we know that's going to be an object. If you wanted to get really specific about how this code is written, then you could create an interface here and you could describe the exact object but in this case, I don't think we need to do that because it's so dynamic then, that it's not really necessary.

So the first thing we're doing is we are using the object class. So this is something in JavaScript. That's why we didn't have to import anything. We're using the Object class and we're grabbing the keys. So that is going to go, we are passing an object to it and it's going to allow us to loop through the keys. So what we've done here is we've created an array out of those key names. So in this case, it was an array of just email. And we're looping through and inside of our map loop, so we're looping through to create a new array, then that's what we're storing in errorContent, we're looping through it and we're saying okay, with each loop, I want you to return an object so in this case, I'm wanting you to return an object that has this key and this value and once again, I used the shorthand syntax here. I could have also just said key to key and I'll keep it here if that's a little bit easier for you to understand.

So I'm saying that for each one of these items, so if the first one is email address, that means we're going to have a key that has the value of email. Now, I also don't want you to get this key confused with this key so you could change this. You could say something. You could call this x and then this is x and then this is x. But I like using the word key because that is what we're iterating through. We're looping through each one of those key elements. And so we're creating an object. The object has two keys. The first one is whatever the name is, so as you're looping through like we saw, the first one was going to be email and then the value, this is that set of errors. So this is going to be for what we saw, this is going to be the error of there's a duplicate email or whatever it said and that is an array. So that's the reason why we still weren't able to just pass this data to the alert because this is still an array.

So now, we come down and we say okay, we have a new variable that we're storing this in called formattedErrors. It's going to be of type array and the reason why I use this return type here is because I want to be 100% clear that I need to call join here at the end because if I tried to pass this data and thought oh, maybe this is a string, then this is going to throw an error when I try to call it in the alert so that's not what we want so I want to be explicit and say I'm passing an array back. That's what this is going to return.

And then the errorContent is going to loop through. So this is where we're looping through everything that we set up here and so I'm looping through this array. I'm grabbing each one of these as a name. That's the way I like to think about them. So I'm grabbing name.key. First one and the only one we had was email. Then name.value, that's what we stored here. That's an array, that's why we're calling join on it. So it could be all the things like duplicate or not valid or whatever it is, whatever the server returns, we're iterating over those and we're just saying just turn that into one long string. If it's one, just make it one, if it's 10, make it 10 and then from there, we're taking formattedErrors and we're saying I want you to put those all together into a string so that we can work with it.

So let's hit Save here, everything's good, everything's still working. Really nice job in going through that. That is definitely, everything we covered gets into much more advanced JavaScript but because of everything you've gone to up to this point, I really felt like you were ready to create these types of functions and now that we have that, we're able to call this from any other part of our application that takes in an error object.

Resources