gRPC with Go - Basic RPC Routines

gRPC With Go Crash Course – Basic RPC Routines

This article is part of the series gRPC With Go Crash Course

In this part of the course, you will start implementing the gRPC servers/clients we setup in the previous exercise.

We will focus on implementing the more basic request-response-type RPCs. In the next exercises, we will look into the more complex stream-based RPCs.

The Starting Point

If you completed the previous exercise, you can continue from where you left off.

Otherwise, to get started, run this command to clone the necessary exercise materials in a convenient folder:

git clone --branch v2-initial-integration https://github.com/preslavmihaylov/go-grpc-crash-course


NOTE:
If you are using GOPATH mode, you should clone the repo exactly in <your-gopath>/src/github.com/preslavmihaylov/go-grpc-crash-course.

Next up, install the libraries you’ll need by executing this at the heart of the repo:

go mod download

This line will install the required dependencies in your $GOPATH.

Your Goal

In this article, we’ll be writing some basic request-response style gRPC routines:

Basic Request-Response Routines

First, take a look around the scaffold and familiarize yourself with what you’re building.

You have three main folders – casino, client, payment_statements

  • casino – this contains the source code for a casino microservice. This will contain the bulk of the backend logic.
  • client – this is a client application, which connects to the casino service and allows the user to use the application via a CLI interface.
  • payment_statements – this contains the source code for a payment statements microservice. It will be solely responsible for generating a user’s payment statement given a list of payments. The casino service will connect to this one and create user payment statements upon request.

All the service schema are in the idl directory.

Finally, you have make_protos.sh, which is a simple bash script which compiles all your protobuf schemas together.

This is a utility script, enabling you to more easily re-compile proto schemas, instead of having to dig in your bash history for the correct protoc command.

The IDLs & initial service integrations are already setup for you. If you’ve completed the previous exercise, then you know how we got here.

What we have left is to implement all the RPCs in our servers/clients. For all the locations where you have to chime in, you have a TODO: Implement comment or a panic in there.

Take a look around and see where all those locations are.

In this exercise, we’ll be focusing on implementing the simpler gRPC routines which don’t involve streams. Conceptually, there is nothing different compared to normal request-response endpoints in an HTTP API.

If you want to attempt the challenge on your own, read on. Otherwise skip to the Full Walkthrough section.

Here’s what you have to do:


In casino/main.go:

  • BuyTokens – this routine takes in a Payment and grants the user tokens equal to Payment.Amount * tokensPerDollar.

    You should store the total amount of user tokens in casinoServer.userToTokens[userID].

    You should also record the payment in the user’s payment history in casinoServer.userToPayments[userID]. The payment amount should be stored as a negative number. (e.g. 5$ -> -5$ payment)

    Finally, return the amount of tokens bought in a &casinopb.Tokens{Count: <tokens-bought>}
  • Withdraw – this routine allows a user to pass in an amount of tokens they own & get the corresponding cash back.

    If the user doesn’t have enough tokens, return an error with a meaningful message (e.g. “not enough tokens to withdraw”).

    Otherwise, subtract the WithdrawRequest.TokensCnt from a user’s token balance (casinoServer.userToTokens).

    Additionally, append a new payment to a user’s payment history equal to tokensCnt / tokensPerDollar. The payment amount should be stored as a positive number.

    Finally, return a casinopb.Payment to the user with their userID + amount of dollars they withdrew.
  • GetTokenBalance – This routine returns the current token balance of a user. The token balance is available in casinoServer.userToTokens.

In client/commands.go:

  • buyTokens – invoke the corresponding BuyTokens routine from the casino server using the gRPC client instance of it – available in global variable client).

    The UserID is available in a global variable username.

    If there was an error, return it. If the call was successful, return a message: Successfully bought {tokensCnt} tokens!.

    The tokensCnt in the above message should be taken from the server response.
  • withdraw – invoke the corresponding Withdraw routine from the casino server.

    If the call was successful, return a message:
    Successfully withdrew {tokensCnt} tokens and got {amountWithdrewn}$!

    Both variables in the above message should be taken from the server’s response.
  • tokenBalance – invoke the corresponding TokenBalance routine from the casino server.

    If the call was successful, return a message:
    Your token balance is {tokenBalance}.

    The token balance should be taken from the server’s response.

Those are all the requirements you have to accomplish as part of this article.

If everything is completed well, this is what the final result should look like after you run all the binaries:

final result of the challenge

In the following section, you’ll find a complete walkthrough of the exercise. Use it in case you get stuck!

Good luck!

For help, refer to the gRPC Go Tutorial.

Full Walkthrough

Remember! Before going through this walkthrough, make sure you’ve attempted to complete the exercise on your own. 

Refer to it if you get stuck or are interested in how I did it.

No cheating! 🙈🙈🙈

Now that we’ve gotten that out of the way, let’s get started!

Step 1. Implement BuyTokens on the server-side

We’ll start by implementing the BuyTokens routine in casino/main.go.

First, we’ll create some simple helper variables.

One for storing the userID in an appropriate format and one for storing the final tokens amount the user’s bought.

We’ll also add a logline to help us verify everything works correctly on the server-side:

Next, we’ll store the new payment in the user’s payment history (with negative amount as per requirement) and add the new tokens to the user’s token balance:

Finally, return a casinopb.Tokens response with the amount of tokens bought:

Step 2. Invoke BuyTokens on the client-side

Now that we have the routine implemented on the server-side, let’s invoke it on the client side in client/commands.go.

There is nothing too fancy in invoking the routine on the client-side. All should be self-explanatory. 

What’s interesting to note, however, is that in contrast to making HTTP requests, making a gRPC request resembles a normal function invocation.

Now run the application and try buying some tokens. This is an example session:

buy tokens test

Step 3. Implement the Withdraw routine

We’ll first implement it server-side in casino/main.go.

Start by logging some debug info & assigning helper variables:

Then, use the function hasEnoughTokens from casino/utils.go to verify that a user can afford to withdraw a given # of tokens:

Use it inside the Withdraw routine and return an error if the user doesn’t have enough tokens on hand:

Next, if the user’s eligible to withdraw the requested # of tokens, add a new payment with positive amount & subtract the tokens from his token balance:

Finally, return a commonpb.Payment response with the amount of dollars the user withdrew:

Now, invoke the routine client-side as we’ve done so far for the other routines:

And finally, test that everything looks good:

withdraw test

Step 4. Implement the TokenBalance routine

This routine is probably the easiest as it’s simply a getter for a user’s token balance.

In casino/main.go:

In client/commands.go:

And that’s all there is to it.

Finally, test that everything we’ve written so far works well:

token balance test

Finale

Congratulations. 👏👏👏

You’ve successfully completed the exercise. 

You should now have a good understanding of how to create basic gRPC routines and how to invoke them from your client applications.

But that’s not all gRPC has to offer.

What about streams? Client-side, server-side?
And what about bidirectional streams?

Don’t worry, we’ll explore that in the following exercises, so stay tuned. 🙌🙌🙌

If you want to view the final solution for this exercise, checkout the v3-simple-rpc branch.

Go to Part 3 – Unidirectional Streams

Site Footer

BulgariaEnglish