Although I agree with the sentiment in the text ("It’s not about just getting the code to work, it’s about completely polished solutions”) I have to say that your first example is the exact antithesis of what you should be doing.
The first (very simple) version — what you call the “junior approach” — is instantly clear to even the most junior developer. You didn’t actually explain what’s wrong with it, but I assume you think it's insufficiently robust - a failed userId, for example, might generate an authentication error from the back-end, or it might exception, or …
So, in the second version — "senior approach" — you’ve added a bunch of tests which try to mind-read the back-end (incorrectly, by the way — I can see at least three failure modes you haven't covered), and throw exceptions which force the caller to clean up the mess (which means the caller needs to understand the inside of this function: the function's boundary is porous). You're also returning a virtually unchecked lump of json to the caller rather than an actual UserData instance (which the function advertises) which means a small change at the back-end can (without warning) break the code that calls this. Compared to the Junior approach: this is less reliable, less comprehensible, less maintainable, less predictable (by the user) and untestable in any meaningful way. What it most definitely is not is “polished”!
I’m sorry to be so critical, but if a “Senior” on any of my teams checked-in an example like this, I'd seriously be questioning his future as a developer. This is an illustration of post-junior code at best, and is certainly far from production standard.