Connect FastAPI & Golang services using gRPC
Tags: python, go, grpc, microservices
Published: 2022-11-06 11:27:09

Hello Devs! Recently I started learning Protocol buffers & gRPC, and gotta tell you, this tech is amazing!

> THIS POST REQUIRES A PRIOR KNOWLEDGE OF GRPC, GOLANG, AND PYTHON

Follow along with this post to get a hands-on demo on how to establish communication between different microservices that are running on different codebases using gRPC.

> Find the code for this post [here](https://github.com/ankit-brijwasi/grpc-demo-with-go-and-fastapi).

## Directory Structure
    fastapi-and-golang-grpc-demo
    |-fastapi
        |-app
        |-env
        |-requirements.txt
    |-protobufs
        |-auth.proto
    |-main.go
    |-Readme.md
    |-go.mod

## Create the auth protobuf file
Open the `auth.proto` file on your favourite code editor, and add the following code to it

```protobuf
syntax = "proto3";
package auth;
option go_package = "auth.utils/auth";


message AuthenticationRequest {
    string token = 1;
}

message AuthenticationResponse {
    int64 user_id       = 1;
    bool  token_valid   = 2;
}

service Auth {
    rpc Authenticate (AuthenticationRequest) returns (AuthenticationResponse);
}
```

> Read more about protocol buffers [here](https://developers.google.com/protocol-buffers/docs/overview).


## Add the Go service
1\. Initialize the go application with
```bash
$ go mod init auth-ms
```

2\. Generate the gRPC code
```bash
$ protoc --go_out=. --go-grpc_out=. protobufs/auth.proto
```

3\. Update the dependencies
```bash
$ go mod tidy
```

4\. Let's create our gRPC server for golang, add the following code in the `main.go` file
```go
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"

	pb "auth-ms/auth.utils/auth"

	"google.golang.org/grpc"
)

var (
	port = flag.Int("port", 50051, "port to run the server on")
)

type server struct {
	pb.UnimplementedAuthServer
}

// extend the rpc service created in auth.proto
func (s *server) Authenticate(ctx context.Context, req *pb.AuthenticationRequest) (*pb.AuthenticationResponse, error) {
        token := req.GetToken()
        log.Printf("Received: %v", token)

        // add some logic to verify token
        return &pb.AuthenticationResponse{UserId: 1, TokenValid: true}, nil
}

func main() {
	flag.Parse()
	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))

	if err != nil {
		log.Fatalln("Unable to start the server on port", *port)
	}

	grpc_server := grpc.NewServer()
	pb.RegisterAuthServer(grpc_server, &server{})
	log.Println("Started server at", lis.Addr())

	if err := grpc_server.Serve(lis); err != nil {
		log.Fatalln("Failed to start server at", lis.Addr())
	}
}
```

5\. Start the gRPC server and keep it opened
```bash
$ go run main.go -port 8080
2022/11/06 16:26:39 Started server at [::]:8080
```

## Add the FastAPI Service
1\. Install the dependencies
```bash
$  pip install fastapi uvicorn grpcio-tools~=1.30
```

2\. Generate the gRPC code
```bash
$ cd ./fastapi/app/
$ python -m grpc_tools.protoc -I ../protobufs --python_out=. --grpc_python_out=. ../protobufs/auth.proto
```

3\. Create the FastAPI server
```python
from fastapi import FastAPI
import grpc

from compiled_pb.auth_pb2_grpc import AuthStub
from compiled_pb.auth_pb2 import AuthenticationRequest

app = FastAPI()


@app.get("/token/verify/")
def verify_token(token: str):
    # gRPC client for making RPC calls to the server
    channel = grpc.insecure_channel("localhost:8080")
    client = AuthStub(channel)
    request = AuthenticationRequest(token=token)
    response = client.Authenticate(request)

    data = {
        "user_id": response.user_id,
        "is_token_valid": response.token_valid
    }
    return data
```

4\. Start the FastAPI sever
```bash
uvicorn main:app --host 127.0.0.1 --port 8000 --reload
INFO:     Will watch for changes in these directories: ['/home/ankit/practice/golang_gRPC/fastapi/app']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [8652] using StatReload
INFO:     Started server process [8654]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
```

Now, go to, [http:127.0.0.1:8000/docs](http:127.0.0.1:8000/docs) and hit the, `/token/verify/` route.

![FastAPI server](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m4p9pmonrwp18zatpnj4.jpg)

VOILÀ, As soon as you hit the api request, there will be an internal RPC call to the go gRPC server.

![golang gRPC server](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ssgrzgvx2lffuc0yj03.jpg)

Happy Coding!😊😇