We know to wrap errors, but how can you make the additional context useful? Here's my opinion.
Hey everyone, today I'm going to show you how I like to use format.ErrorF to handle errors with better context. I'm going to show you with an example with a fake database error, because typically this is where I find wrapping can have the most value. When you're doing something and interacting with a third party, where maybe you don't get the most clear error message back because you don't control the error message, we can add some context by using format.ErrorF to be able to make it clearer to us and future readers exactly what went wrong here.
So here's a simple function that I wrote earlier. I'm going to import the errors package and effectively just fetches the user from a database. So let's imagine this was a real query. We tried to make a request and it's invalid. You may even get something like this which comes out often. Maybe you get an error like this where it's not entirely sure what it means.
So we've all seen functions and errors like this. So let's extend our example a little bit. So now what we have is we have like a service style function where we make a call to get user profile. Get user profile makes a call to our database and in our database we return the same error. So an invalid query. Now what we can do is we can actually wrap that error using format.ErrorF to say fail to fetch profile for user %d and w.
So let's run this now and see what the output is. And now we get this. Fail to fetch profile for user zero. Invalid query. Now imagine this shows up in your logs. We have context about the function that was called which is this fetch profile. Maybe you could make it even clearer by changing this to get user profile. We've got a user ID we can investigate and then we've got the invalid query which is the actual error back from here.
So using format.ErrorF is really good practice in my opinion. Whenever you're trying to... So why does any of this matter? In a real app you're going to have dozens of database calls. You're going to be fetching profiles, orders, settings. The errors that come back from the database may not be that descriptive or helpful. So wrapping it with this function gives you a trail. And since we can use the %w the original error is preserved.
So you can still inspect it programmatically if necessary using errors.is. This is really handy for debugging.