Skip to content
Santekno.com | Level Up Your Engineering Skills
ID
📖 0%
23 Sep 2025 · 5 mnt baca ·Artikel 107 / 110
Go

107. Studi Kasus: Menyambungkan Frontend gRPC-Web (JavaScript) dengan Backend Go

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

Dalam beberapa tahun terakhir, pola komunikasi antara aplikasi frontend dan backend terus berevolusi. REST API memang menjadi primadona, namun pola tersebut mulai “direcoki” oleh protokol komunikasi yang lebih efisien dan modern bernama gRPC. Salah satu kekuatan gRPC adalah dukungannya pada protobuf (Protocol Buffers) yang memungkinkan komunikasi data antar-generate code dengan performa prima.

Namun, adopsi gRPC pada frontend web tidak bisa langsung semulus pada mobile atau backend. Browser tidak mendukung langsung HTTP/2–protokol yang menjadi standar untuk gRPC murni. Di sinilah gRPC-Web hadir.

Artikel kali ini membahas studi kasus konkret: menyambungkan frontend JavaScript (React) yang menggunakan gRPC-Web, ke backend Go yang menjalankan server gRPC konvensional. Saya akan bagikan alur langkah-demi-langkah, studi kode, simulasi request, dan praktik baik dalam pengembangan ini.


Mengapa gRPC-Web?

Sebelum menyelam ke kode, mari kita bahas sebentar kenapa kita perlu repot-repot menggunakan gRPC dan bukan sekadar REST:

RESTgRPC
Data format: text (JSON)Data format: Binary (protobuf)
Overhead serializationSangat efisien, extensible serialization
No contract direkStrictly defined via .proto (contract)
HTTP/1.1HTTP/2 (lebih cepat, multiplexed)
Kurang ideal untuk streamingMendukung full-duplex streaming
Mudah diakses di browserButuh tambahan (gRPC-Web)

Pada aplikasi single-page modern, pengiriman dan penerimaan data besar, up-to-date, dan efisien menjadi penting. gRPC di sisi backend sangat memudahkan, namun frontend berbasis browser membutuhkan penyesuaian via gRPC-Web.


Diagram Arsitektur

Sebelum kode, inilah skema alurnya:

MERMAID
flowchart TD
    Client[gRPC-Web aplikasi JavaScript (Browser)]
        -->|request (HTTP/1.1)| Envoy[gRPC-Web Proxy (Envoy)]
        -->|translasi ke HTTP/2| GoServer[gRPC Server (Go)]
    GoServer
        -->|response (HTTP/2)| Envoy
        -->|HTTP/1.1 response| Client

Jadi, alur datanya adalah:

  1. JavaScript client (browser) => request via gRPC-Web (HTTP/1.1).
  2. Proxy Envoy atau plugin lain translasi request ke HTTP/2 (untuk backend gRPC Go).
  3. Response dikembalikan ke browser.

Persiapan: Definisikan Contract (.proto)

Kunci sukses gRPC adalah single source of truth dalam format .proto. Berikut contoh sederhana di folder proto/greet.proto:

protobuf
 1syntax = "proto3";
 2
 3package greet;
 4
 5service Greeter {
 6    rpc SayHello (HelloRequest) returns (HelloReply) {}
 7}
 8
 9message HelloRequest {
10    string name = 1;
11}
12
13message HelloReply {
14    string message = 1;
15}

Properti seperti inilah yang mendasari kedua sisi—frontend & backend—agar selalu sinkron tanpa “nyontek” API!


1. Setup Backend gRPC di Go

A. Generate Protobuf

Instalasi tools untuk Go biasanya lewat:

sh
1go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
2go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

Compile:

sh
1protoc -I proto/ \
2    --go_out=pb --go_opt=paths=source_relative \
3    --go-grpc_out=pb --go-grpc_opt=paths=source_relative \
4    proto/greet.proto

B. Implementasi Service di Go

File: main.go

go
 1package main
 2
 3import (
 4    "context"
 5    "log"
 6    "net"
 7    "google.golang.org/grpc"
 8    pb "your-module/pb/greet"
 9)
10
11type server struct {
12    pb.UnimplementedGreeterServer
13}
14
15func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
16    return &pb.HelloReply{Message: "Hello, " + req.Name + "!"}, nil
17}
18
19func main() {
20    lis, err := net.Listen("tcp", ":50051")
21    if err != nil {
22        log.Fatalf("Failed to listen: %v", err)
23    }
24    s := grpc.NewServer()
25    pb.RegisterGreeterServer(s, &server{})
26    log.Println("gRPC Go server running on :50051")
27    if err := s.Serve(lis); err != nil {
28        log.Fatalf("Failed to serve: %v", err)
29    }
30}

2. Setup Proxy gRPC-Web (Envoy)

Karena browser hanya bisa HTTP/1.1 + CORS, kita perlu proxy. Salah satu opsi yang battle-proven adalah Envoy. Contoh konfigurasi minimal (envoy.yaml):

yaml
 1static_resources:
 2  listeners:
 3  - address:
 4      socket_address:
 5        address: 0.0.0.0
 6        port_value: 8080
 7    filter_chains:
 8    - filters:
 9      - name: envoy.filters.network.http_connection_manager
10        typed_config:
11          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
12          codec_type: auto
13          stat_prefix: ingress_http
14          route_config:
15            name: local_route
16            virtual_hosts:
17            - name: backend
18              domains: ["*"]
19              routes:
20              - match:
21                  prefix: "/"
22                route:
23                  cluster: greeter_service
24          http_filters:
25          - name: envoy.filters.http.grpc_web
26          - name: envoy.filters.http.cors
27          - name: envoy.filters.http.router
28  clusters:
29  - name: greeter_service
30    connect_timeout: 0.25s
31    type: logical_dns
32    lb_policy: round_robin
33    http2_protocol_options: {}
34    load_assignment:
35      cluster_name: greeter_service
36      endpoints:
37      - lb_endpoints:
38        - endpoint:
39            address:
40              socket_address:
41                address: host.docker.internal
42                port_value: 50051

Jalankan dengan Docker:

sh
1docker run --rm -it -v $(pwd)/envoy.yaml:/etc/envoy/envoy.yaml -p 8080:8080 envoyproxy/envoy:v1.21-latest

Jika backend Go ada di host, gunakan host.docker.internal di cluster Envoy.


3. Setup Frontend gRPC-Web (JavaScript/React)

A. Generate Stub JS dari .proto

Gunakan plugin protoc-gen-grpc-web :

sh
1npm install -g protoc-gen-grpc-web
2protoc -I=proto \
3    greet.proto \
4    --js_out=import_style=commonjs:./src/pb \
5    --grpc-web_out=import_style=commonjs,mode=grpcwebtext:./src/pb

Di package.json, tambahkan devDependencies:

json
1"dependencies": {
2    "grpc-web": "^1.4.2"
3}

B. Membuat Client gRPC-Web

File: src/App.js

javascript
 1import React, { useState } from 'react';
 2import { GreeterClient } from './pb/greet_grpc_web_pb';
 3import { HelloRequest } from './pb/greet_pb';
 4
 5function App() {
 6  const [name, setName] = useState('');
 7  const [reply, setReply] = useState('');
 8
 9  const client = new GreeterClient('http://localhost:8080', null, null);
10
11  const sayHello = () => {
12    const request = new HelloRequest();
13    request.setName(name);
14    client.sayHello(request, {}, (err, response) => {
15      if (err) {
16        setReply('Error: ' + err.message);
17      } else {
18        setReply(response.getMessage());
19      }
20    });
21  };
22  
23  return (
24    <div>
25      <h1>gRPC-Web Demo: Say Hello</h1>
26      <input value={name} onChange={e => setName(e.target.value)} />
27      <button onClick={sayHello}>Send</button>
28      <p>Server replies: {reply}</p>
29    </div>
30  );
31}
32
33export default App;

4. Simulasi Request dengan Client

Misal user mengetik “Kevin” dan submit, inilah alur request-response (disimulasikan dari network devtools):

  1. HTTP/1.1 POST ke http://localhost:8080/greet.Greeter/SayHello
    Content-Type: application/grpc-web-text
  2. Envoy menerima dan forward ke grpc server Go via HTTP/2.
  3. Backend membalas: message "Hello, Kevin!"
  4. Envoy encoding response ke format grpc-web dan diantarkan ke browser.

Troubleshooting & Praktik Baik

MasalahPenyebab & Solusi
CORS error di JS clientPastikan filter Envoy sudah enable cors, konfigurasi allow_origin
Error UNAVAILABLE di clientProxy Envoy belum terkoneksi ke backend Go, cek IP/port
Unexpected content-typePastikan client menggunakan grpcwebtext mode dan stub JS hasil generate
Server Go tidak handle requestRegistrasi service sudah benar, lihat log server Go

Kesimpulan

Dengan arsitektur di atas, kita dapat merasakan kekuatan gRPC di frontend browser meski ada batasan HTTP/2 dan CORS. Komunikasi antar service jadi lebih terstandarisasi, aman dari miss API, serta maintenance-lah yang lebih long-lasting!

Proses nyata mengadopsi gRPC-Web seperti ini memang sedikit “engineering-heavy” dibanding pola REST. Namun untuk aplikasi enterprise, microservices, dan real-time, investasi ini sepadan.

Semoga studi kasus ini membantu Anda menyatukan frontend JavaScript modern dengan backend Go berbasis gRPC, dan siap membangun sistem web yang scalable, modular, dan future-proof. Selamat bereksperimen!


Referensi

Artikel Terkait

💬 Komentar