Skip to content

gRPC-Web with Golang and VueJS: An alternative to REST and GraphQL

Posted on

gRPC-Web is a JavaScript client library that enables web apps to communicate directly with gRPC backend services, without requiring an HTTP server to act as an intermediary.

With gRPC-Web, you can now easily build truly end-to-end gRPC application architectures by defining your client and server-side data types and service interfaces with Protocol Buffers.

gRPC is a super-fast, super-efficient Remote Procedure Call (RPC) system that will make your microservices talk to each other. You can found more details in the official gRPC documentation and my previous post Building microservices in Go and Python using gRPC.

gRPC-Web, just like gRPC, lets you define the service "contract" between client (web) and backend gRPC services using Protocol Buffers. The client can then be auto generated. This development process removes the need to manage concerns such as creating custom JSON seralization and deserialization logic, wrangling HTTP status codes, managing content type negotiation etc.

Advantages of using gRPC-Web

  • End-to-end gRPC: Enables you to craft your entire RPC pipeline using Protocol Buffers. Your client can interacty directlly with one or more gRPC servers, just calling the definied functions.
  • Tighter coordination between frontend and backend teams: With the entire RPC pipeline defined using Protocol Buffers, you no longer need to have your "microservices teams" alongside your "client team." The client-backend interaction is just one more gRPC layer amongst others.
  • Easily generate client libraries: All of your service's client libraries can be gRPC libraries. Need client libraries for Rust, Python, Java, and 4 other languages? You no longer need to write HTTP clients for all of them.

gRPC-Web application example

I started with a simple accounts.proto definition like this:

syntax = "proto3";

package private;
option go_package = "proto";

service AccountService {
    rpc Create(User) returns (User) {}
    rpc AuthenticateByEmailAndPassword(User) returns (Account) {}
}

message User {
    string email = 1;
    string password = 2;
}

message Account {
    string token = 1;
}

message Nothing {}

And I run the following commands to generate the server-side and CommonJS client-side code:

protoc -I proto proto/*.proto --proto_path=./proto --go_out=plugins=grpc:./backend/proto
protoc -I proto proto/*.proto --js_out=import_style=commonjs:./frontend/proto --grpc-web_out=import_style=commonjs,mode=grpcwebtext:./frontend/proto

The previous commands created the file frontend/proto/accounts_grpc_web_pb.js containing the service implementation and frontend/proto/accounts_pb.js containing the type definition.

After that, I implemented some code in Go and created the request call in Javascript. It's something like the code below:

import (
    ...
    pb "backend/proto"
)

func (instance *AccountServer) Create(ctx context.Context, req *pb.User) (*pb.User, error) { 
    user := structs.User{
        Email:    req.Email,
        Password: req.Password,
    }
    query := `INSERT INTO accounts (email, password) VALUES (:email, :password);`
    conn := instance.db.GetConnection()
    _, err := conn.NamedExec(query, &user)
    return &pb.User{Email: user.Email}, err
}

And I call the create gRPC function in Javascript:

import { Account, User } from '../../proto/accounts_pb'
import { AccountServicePromiseClient } from '../../proto/accounts_grpc_web_pb'

export default class {
    constructor () {
        this.client = new AccountServicePromiseClient('http://localhost:9000', null, null)
    }

    async create (user) {
        const req = new User()
        req.setEmail('me@gustavohenrique.com')
        req.setPassword('verystrongpassword')
        try {
            const res = await this.client.create(req, {})
            return res.getEmail()
        } catch (err) {
            console.error(err.message)
            throw err
        }
    }
}

The full source code using Golang and VueJS (Quasar Framework) can be found in my GitHub repository.

Conclusion

Now you are wondering "Should I adopt gRPC?"

gRPC is a robust architecture that has several supporters. Companies like Google, Netflix and Dropbox already use it in production. With a low learning curve, new developers on a gRPC project can be productive quickly. The definition of types and services in Protocol Buffer works as documentation too - whoever consumes the service gets to know what to send in the request and what can be received in the response.

gRPC-Web is an excellent option for web developers. It brings portability, excellent performance and a sophisticated protocol for use on the web or mobile front-end.