MARTIN OMANDER: Hey, Grant.
I'm developing a Cloud Function and I'm having issues
troubleshooting it.
GRANT TIMMERMAN: Oh, have you tried debugging your function
locally?
MARTIN OMANDER: Oh no, I haven't.
GRANT TIMMERMAN: Let's pair program together.
[MUSIC PLAYING]
So Martin, what's the issue?
Don't you write perfect code that works
the first time you run it?
MARTIN OMANDER: I wish.
Let me give you some background.
I'm building a Cloud Function to share all the cute animal
photos you sent me.
Testing the function is getting fairly complicated.
And I keep getting an error, trying to fix it, deploy,
wait a minute, test again.
It's taking a lot of time.
GRANT TIMMERMAN: Yeah, that does sound time-consuming and risky,
especially if you're testing in production.
So let's go and I'll check out your code
and your function locally on my machine.
MARTIN OMANDER: Sounds great.
GRANT TIMMERMAN: So here, I've checked out your code.
You're a pretty good coder, but--
sorry.
Focus.
Focus, Grant.
Let me go and show you how you can go
and run your function locally.
So in this case, we got a Node function.
To run our function locally, I'll
first install the Google Cloud Functions Framework
with npm i @google cloud/functions framework.
MARTIN OMANDER: All right.
I'm a pretty good coder, huh?
All right.
So this is Node.
But what about languages other than Node?
My coworker, for example, uses Java.
GRANT TIMMERMAN: Oh, great question, Martin.
So this library-- the Functions Framework--
is available in all Cloud Function runtimes.
So the process is pretty similar between Python, Go, Java, Ruby,
PHP, and .NET.
In fact, there's a link in the description of this video down
below with documentation with detailed instructions
for those languages.
So next, we can go and just use the Functions Framework
for that language as a library, so you
can run your function locally.
Let's add a start script so we can simply run npm start.
This will start our localhost server serving our function.
MARTIN OMANDER: Neat.
So we can just curl this localhost URL
and test the function locally?
Hm.
Mhm.
Oh, it looks like we're getting the same error.
Darn.
GRANT TIMMERMAN: No, Martin, so this
is the error we want to see.
It's actually the same error that we're
seeing in production.
But now we can go and test locally.
MARTIN OMANDER: Oh, I see.
All right.
So how do we debug this locally?
GRANT TIMMERMAN: Well, you can go use console.log statements,
which I sometimes do.
Don't tell my manager.
But this can be a little bit cumbersome, especially
with a larger application.
So let's setup the Node debugger.
MARTIN OMANDER: That sounds good.
Are you saying that I can use the normal Node debugger?
GRANT TIMMERMAN: Yes.
So Node comes with a debugger out of the box.
We can simply attach this debugger
to our Node process running our function.
So in VS Code, let's use the Attach command.
MARTIN OMANDER: Oh, nice.
OK.
All right.
So oh, I see the status bar change from blue to orange.
GRANT TIMMERMAN: Yes.
So that indicates that we've successfully
attached our debugger.
Now let's add a breakpoint in the beginning of our function.
[VOCALIZING]
MARTIN OMANDER: Good, good.
All right.
And now let's run our function, see if we
can catch this pesky error.
GRANT TIMMERMAN: All right.
I'll go and curl our localhost URL.
MARTIN OMANDER: OK.
I see the editor has paused execution on the breakpoint?
GRANT TIMMERMAN: Yeah.
In fact, if we go and hover over some variables,
we can see the current values.
So let's go.
MARTIN OMANDER: Oh, I see.
Oh, look at that.
Oh, it looks like I used req.params
where it should be req.query.
Would you fix that, Grant?
GRANT TIMMERMAN: Oh, yeah.
Sure.
It's a silly typo?
MARTIN OMANDER: Yeah.
GRANT TIMMERMAN: And it looks like there's a few more
errors here.
I'll edit them.
And I'm just done.
So now that we've edited our code,
we need to restart the function for it to take effect.
One second.
Let me go and just cancel the process,
restart it, and try again.
And boom.
MARTIN OMANDER: This is great.
But Grant, the function accesses the Firestore Database
in the cloud.
How come that worked when you ran the function
on your local machine?
GRANT TIMMERMAN: Oh, great question, Martin.
So the client library used in the function
picks up the local credentials from gcloud.
In fact, I ran a special command to get these credentials.
These are called application default credentials.
These default credentials are the exact same credentials
that you see with Cloud Functions that's
used in production.
So to get this, I ran the command
gcloud auth application-default login before I set this.
So remember that Firestore isn't running on our local machine.
It's the function is using the client library and our auth
to call the Firestore Database on our cloud project.
MARTIN OMANDER: Oh, I see.
So Grant, how about we close the loop
and deploy the code to Google Cloud Functions?
GRANT TIMMERMAN: Sounds great.
Let me run the deploy script here, gcloud functions deploy.
MARTIN OMANDER: All right, it looks like it deployed.
And now let's curl the function.
GRANT TIMMERMAN: Great.
Curling the function with our URL.
And it looks like it works.
It looks like we don't see the error of an undefined variable
anymore.
I'll click the photo link and see if it actually worked.
Aw, look at that cute puppy, Martin.
MARTIN OMANDER: [LAUGHS] Yes, so furry.
I'm happy the function works.
GRANT TIMMERMAN: Well, it sounds like we definitely
deserve a coffee break.
MARTIN OMANDER: Yes, we've earned it.
Great.
Thank you, everyone, for watching.
If you have any questions for me or Grant,
please add them in the comments below.
Also, please let us know if you have
another serverless topic that you'd like
to see us cover in a video.
Bye for now.
[MUSIC PLAYING]