{"id":19149365,"url":"https://github.com/restuwahyu13/node-grpc","last_synced_at":"2025-05-07T04:42:46.946Z","repository":{"id":114456754,"uuid":"331579191","full_name":"restuwahyu13/node-grpc","owner":"restuwahyu13","description":"Basic concept GRPC and sample implementation using nodejs and typescript","archived":false,"fork":false,"pushed_at":"2023-01-17T15:18:05.000Z","size":53,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-07T04:42:40.699Z","etag":null,"topics":["grpc","grpc-node","grpc-service","http2","node","nodejs-server","rpc-server"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/restuwahyu13.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-01-21T09:34:11.000Z","updated_at":"2025-02-20T02:36:05.000Z","dependencies_parsed_at":"2023-06-08T00:30:28.843Z","dependency_job_id":null,"html_url":"https://github.com/restuwahyu13/node-grpc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/restuwahyu13%2Fnode-grpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/restuwahyu13%2Fnode-grpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/restuwahyu13%2Fnode-grpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/restuwahyu13%2Fnode-grpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/restuwahyu13","download_url":"https://codeload.github.com/restuwahyu13/node-grpc/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252816517,"owners_count":21808702,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["grpc","grpc-node","grpc-service","http2","node","nodejs-server","rpc-server"],"created_at":"2024-11-09T08:07:56.962Z","updated_at":"2025-05-07T04:42:46.893Z","avatar_url":"https://github.com/restuwahyu13.png","language":"JavaScript","readme":"# GRPC Tutorial\n\n## GRPC (Google Remote Procedure Call)\n\nadalah sebuah framework rpc yang dibuat oleh google tepatnya pada tahun 2015 dan grpc juga termasuk kedalam open source `Cloud Native Computing Fondation (CNCF)` seperti docker dan kubernetes yang sama - sama juga dibuat oleh google, konsep umum dari grpc sangat mirip dengan `rest api` atau `graphql` yang dimana digunakan untuk saling mengirim request dan response baik itu dari sisi client ataupun server, yang membedakan grpc dari `rest api` dan `graphql` adalah simplenya, grpc itu sendiri dibangun di atas protocol buffer dan http2, sehingga proses pengiriman request data menjadi lebih cepat dan efisien, dengan menggunakan protocol buffer setiap request yang dikirim dari client ke server akan berbentuk sebuah buffer, sehingga pengiriman data menjadi lebih cepat dari pada json, dikarenan buffer memiliki ukuran size yang jauh lebih kecil dari pada json dan juga lebih mudah dibaca oleh mesin, grpc juga menggunakan protofile sebagai smart contract yang digunakan untuk menjembatani interaksi antara client dan server agar bisa untuk saling mengirim request atau response.\n\n\n## Protocol Buffer\n\nadalah formating data open source yang digunakan untuk membuat serialisasi data, yang dimana anda sendiri dapat menentukan struktur data yang anda inginkan hanya dalam 1x tulis dan bisa digunakan di berbagai bahasa pemerograman jenis apapun, protocol buffer sendiri memiliki ukururan size yang jauh lebih kecil dari json dan juga lebih cepat dari pada json, info lebih detail terkait protobuf bisa cek [disini](https://developers.google.com/protocol-buffers).\n\n+ **syntax** digunakan untuk menentukan format protocol buffer yang akan digunakan untuk menulis schema, format support yang bisa digunakan ada proto2 versi lama dan versi baru proto3\n+ **package** digunakan sebagai unique identifikasi schema untuk menghindari duplikasi schema yang sama, ketika sesudah digenerate menjadi sebuah file stub\n+ **import** digunakan untuk mengimport ekternal library yang akan di gunakan didalam schema\n+ **service** digunakan sebagai namespace untuk mengrouping remote method yang akan digunakan\n+ **rpc** digunakan untuk melabelkan remote method\n+ **message** digunakan untuk menentukan request atau response untuk digunakan oleh rpc method\n+ **repeated** digunakan untuk mengconvert type object to type array\n+ **optional** digunakan untuk mengecualikan property schema\n+ **schema**\n\n```js\nsyntax = \"proto3\";\npackage users;\n\nimport \"google/protobuf/any.proto\";\n\nservice Users {\n  rpc CreateUnary(User) returns (Response) {}\n  rpc CreateClientStreaming(stream User) returns (Response) {}\n  rpc CreateServerStreaming(User) returns (stream Response) {};\n  rpc CreateBidirectionalStreaming(stream User) returns (stream Response) {};\n}\n\nmessage Empty {}\n\nmessage UserId { int32 id = 1; }\n\nmessage User {\n  int32 id = 1;\n  string name = 2;\n  int32 age = 3;\n}\n\nmessage UserList { repeated User users = 1; }\n\nmessage Response {\n  int32 stat_code = 1;\n  string stat_msg = 2;\n  optional google.protobuf.Any data = 3\n}\n```\n\n## RPC\n\nadalah protokol yang menyediakan sebuah proses komunikasi antar proses, yang dimana mengijinkan sebuah program untuk berkomunikasi satu sama lain pada server yang berbebeda dan umumnya protokol RPC digunakan untuk membangun aplikasi client-server yang terdistribusi.\n\n## GRPC Concept\n\n+ ### Unary RPC\n\nadalah sebuah konsep rpc yang dimana client hanya bisa mengirim sebuah request ke sisi server hanya 1x dalam satu waktu, begitu juga untuk sisi server dimana server hanya bisa mengirim sebuah response ke sisi client hanya 1x dalam satu waktu, tetapi jika dari sisi server mengirim multiple response seperti `Contoh Server Response Not Support` maka yang terjadi adalah, client dapat mengirim request ke sisi server dan akan di terima oleh server, tetapi client tidak akan pernah mendapatkan response balikan dari server, dikarenakan sisi client mengalami bottleneck, karena request yang di berikan oleh server tidak pernah di terima oleh client.\n\n  ##### Contoh Client Request Support\n\n  ```ts\n  // set request from sending data into server from client\n  const reqBody = new User()\n  reqBody.setId(1)\n  reqBody.setName('jane doe')\n  reqBody.setAge(28)\n\n  // send data from client into server and get response from server after server received data from client\n  client.createUnary(reqBody, (err: ServiceError, res: Response): void =\u003e {\n    if (err) console.error('Error: ', err)\n    console.log(res.toObject())\n  })\n  ```\n\n  ##### Contoh Server Response Support\n\n  ```ts\n  export function createUnary(call: ServerUnaryCall\u003cUser, Response\u003e, callback: sendUnaryData\u003cResponse\u003e): void {\n    const errRes: ServerErrorResponse = { name: '', message: '' }\n    const res: InstanceType\u003ctypeof Response\u003e = new Response()\n\n    if (!call.request.toObject()) {\n      // sending response error into client, after server received request body from client\n      errRes.name = 'CreateUnary'\n      errRes.code = status.PERMISSION_DENIED\n      errRes.message = 'Create new user failed'\n\n      callback(errRes, null)\n    } else {\n      console.log(`Unary:${new Date().toISOString()} - Request body from client: `, call.request.toObject())\n\n      // set response and send success into client, after server received request body from client\n      res.setStatCode(200)\n      res.setStatMsg('Create new user successfully')\n\n      callback(null, res)\n    }\n  }\n  ```\n\n  ##### Contoh Client Request Not Support\n\n  ```ts\n  // set request from sending data into server from client\n  const reqBody = new User()\n  reqBody.setId(1)\n  reqBody.setName('jane doe')\n  reqBody.setAge(28)\n\n  const reqBody2 = new User()\n  reqBody2.setId(2)\n  reqBody2.setName('john doe')\n  reqBody2.setAge(30)\n\n  // send data from client into server and get response from server after server received data from client\n  client.createUnary(reqBody, reqBody2, (err: ServiceError, res: Response): void =\u003e {\n    if (err) console.error('Error: ', err)\n    console.log(res.toObject())\n  })\n  ```\n\n  ##### Contoh Server Response Not Support\n\n  ```ts\n  export function createUnary(call: ServerUnaryCall\u003cUser, Response\u003e, callback: sendUnaryData\u003cResponse\u003e): void {\n    const errRes: ServerErrorResponse = { name: '', message: '' }\n    const res: InstanceType\u003ctypeof Response\u003e = new Response()\n\n    if (!call.request.toObject()) {\n      // sending response error into client, after server received request body from client\n      errRes.name = 'CreateUnary'\n      errRes.code = status.PERMISSION_DENIED\n      errRes.message = 'Create new user failed'\n\n      callback(errRes, null)\n    } else {\n      console.log(`Unary:${new Date().toISOString()} - Request body from client: `, call.request.toObject())\n\n      // set response and send success into client, after server received request body from client\n      res.setStatCode(200)\n      res.setStatMsg('Create new user successfully')\n      callback(null, res)\n\n      res.setStatCode(200)\n      res.setStatMsg('Create new user successfully2')\n      callback(null, res)\n    }\n  }\n  ```\n\n\n+ ### Client Streaming RPC\n\nadalah sebuah konsep rpc yang dimana client dapat mengirim sebuah request kesisi server lebih dari 1x dalam 1 waktu secara berurutan seperti `Contoh Client Request Support 2`, dikarenakan client menggunakan event streaming untuk mengirim sebuah request data ke sisi server, tetapi sebaliknya sisi server tidak dapat mengirim sebuah response lebih dari 1x dalam 1 waktu secara berurutan, tetapi jika dari server mengirimkan multiple response seperti `Contoh Server Response Not Support` maka yang terjadi adalah, server tidak dapat menerima request yang di berikan oleh client, tetapi client dapat menerima response balikan dari sisi server, dikarenakan sisi server mengalami bottleneck, karena request yang di berikan oleh client tidak pernah di terima oleh server.\n\n\n  ##### Contoh Client Request Support\n\n  ```ts\n  // get response back from server after server received data from client\n  const stream: ClientWritableStream\u003cUser\u003e = client.createClientStreaming((err: ServiceError, response: Response): void =\u003e {\n    if (err) console.error('Error: ', err)\n    console.log(response.toObject())\n  })\n\n  // set request data from client into server\n  const reqBody = new User()\n  reqBody.setId(3)\n  reqBody.setName('restu wahyu saputra')\n  reqBody.setAge(24)\n\n  // send request data into server from client\n  stream.write(reqBody)\n  stream.end()\n  ```\n\n  ##### Contoh Client Request Support 2\n\n  ```ts\n  // get response back from server after server received data from client\n  const stream: ClientWritableStream\u003cUser\u003e = client.createClientStreaming((err: ServiceError, response: Response): void =\u003e {\n    if (err) console.error('Error: ', err)\n    console.log(response.toObject())\n  })\n\n  // set request data from client into server\n  const reqBody = new User()\n  reqBody.setId(1)\n  reqBody.setName('jane doe')\n  reqBody.setAge(28)\n\n  const reqBody2 = new User()\n  reqBody2.setId(2)\n  reqBody2.setName('john doe')\n  reqBody2.setAge(30)\n\n  // send request data into server from client\n  stream.write(reqBody)\n  stream.write(reqBody2)\n  stream.end()\n  ```\n\n  ##### Contoh Server Response Support\n\n  ```ts\nexport function createClientStreaming(stream: ServerReadableStream\u003cUser, Response\u003e, callback: sendUnaryData\u003cResponse\u003e): void {\n\tconst res: InstanceType\u003ctypeof Response\u003e = new Response()\n\n\tstream.on('data', (chunk: User): void =\u003e {\n\t\tconst res: ServerErrorResponse = { name: '', message: '' }\n\n\t\tif (!chunk.toObject()) {\n\t\t\t// set response and send error into client, after server received request body from client\n\t\t\tres.name = 'createClientStreaming'\n\t\t\tres.code = status.PERMISSION_DENIED\n\t\t\tres.message = 'Create new user failed'\n\n\t\t\tcallback(res, null)\n\t\t}\n\n\t\tconsole.log(`ClientStreaming:${new Date().toISOString()} - Request body from client: `, chunk.toObject())\n\t})\n\n\tstream.on('end', (): void =\u003e {\n\t\t// set response and sending success into client, after server received request body from client\n\t\tconst res: InstanceType\u003ctypeof Response\u003e = new Response()\n\t\tres.setStatCode(200)\n\t\tres.setStatMsg('Create new user successfully')\n\n\t\tcallback(null, res)\n\t})\n}\n  ```\n\n  ##### Contoh Server Response Not Support\n\n  ```ts\nexport function createClientStreaming(stream: ServerReadableStream\u003cUser, Response\u003e, callback: sendUnaryData\u003cResponse\u003e): void {\n\tconst res: InstanceType\u003ctypeof Response\u003e = new Response()\n\n\tstream.on('data', (chunk: User): void =\u003e {\n\t\tconst res: ServerErrorResponse = { name: '', message: '' }\n\n\t\tif (!chunk.toObject()) {\n\t\t\t// set response and send error into client, after server received request body from client\n\t\t\tres.name = 'createClientStreaming'\n\t\t\tres.code = status.PERMISSION_DENIED\n\t\t\tres.message = 'Create new user failed'\n\n\t\t\tcallback(res, null)\n\t\t}\n\n\t\tconsole.log(`ClientStreaming:${new Date().toISOString()} - Request body from client: `, chunk.toObject())\n\t})\n\n\tstream.on('end', (): void =\u003e {\n\t\t// set response and sending success into client, after server received request body from client\n\t\tconst res: InstanceType\u003ctypeof Response\u003e = new Response()\n\t\tres.setStatCode(200)\n\t\tres.setStatMsg('Create new user successfully')\n\t\tcallback(null, res)\n\n\t\tres.setStatCode(200)\n\t\tres.setStatMsg('Create new user successfully2')\n\t\tcallback(null, res)\n\t})\n}\n  ```\n\n+ ### Server Streaming RPC\n\nadalah sebuah konsep rpc yang dimana client tidak dapat mengirim sebuah request kesisi server lebih dari 1x dalam 1 waktu secara berurutan seperti `Contoh Client Request Not Support`, tetapi sebaliknya sisi server dapat mengirim sebuah response lebih dari 1x dalam 1 waktu secara berurutan seperti `Contoh Server Response Support 2`, dikarenakan server menggunakan event streaming untuk mengirim sebuah response data ke sisi client.\n\n\n  ##### Contoh Client Request Support\n\n  ```ts\n  // set request data from client into server\n  const reqBody = new User()\n  reqBody.setId(1)\n  reqBody.setName('jane doe')\n  reqBody.setAge(28)\n\n  //  send request data into server from client and get response back from server after server received data from client\n  const stream: ClientReadableStream\u003cResponse\u003e = client.createServerStreaming(reqBody)\n\n  stream.on('data', (response: Response): void =\u003e {\n    console.log(response.toObject())\n  })\n  ```\n\n  ##### Contoh Server Response Support\n\n  ```ts\n  export function createServerStreaming(stream: ServerWritableStream\u003cUser, Response | ServerErrorResponse\u003e): void {\n    const res: InstanceType\u003ctypeof Response\u003e = new Response()\n\n    if (!stream.request.toObject()) {\n      // sending response and send error into client, after server received request body from client\n      res.setStatCode(400)\n      res.setStatMsg('Create new user failed')\n\n      stream.write(res)\n      stream.end()\n    } else {\n      console.log(`ServerStreaming:${new Date().toISOString()} - Request body from client: `, stream.request.toObject())\n\n      // set response and send error into client, after server received request body from client\n      res.setStatCode(200)\n      res.setStatMsg('Create new user successfully')\n\n      stream.write(res)\n      stream.end()\n    }\n  }\n  ```\n\n  ##### Contoh Server Response Support 2\n\n  ```ts\n  export function createServerStreaming(stream: ServerWritableStream\u003cUser, Response | ServerErrorResponse\u003e): void {\n    const res: InstanceType\u003ctypeof Response\u003e = new Response()\n\n    if (!stream.request.toObject()) {\n      // sending response and send error into client, after server received request body from client\n      res.setStatCode(400)\n      res.setStatMsg('Create new user failed')\n\n      stream.write(res)\n      stream.end()\n    } else {\n      console.log(`ServerStreaming:${new Date().toISOString()} - Request body from client: `, stream.request.toObject())\n\n      // set response and send error into client, after server received request body from client\n      res.setStatCode(200)\n      res.setStatMsg('Create new user successfully')\n      stream.write(res)\n\n      res.setStatCode(200)\n      res.setStatMsg('Create new user successfully2')\n      stream.write(res)\n\n      stream.end()\n    }\n  }\n  ```\n\n  ##### Contoh Client Request Not Support\n\n  ```ts\n  // set request data from client into server\n  const reqBody = new User()\n  reqBody.setId(1)\n  reqBody.setName('jane doe')\n  reqBody.setAge(28)\n\n  const reqBody2 = new User()\n  reqBody.setId(2)\n  reqBody.setName('john doe')\n  reqBody.setAge(30)\n\n\n  //  send request data into server from client and get response back from server after server received data from client\n  const stream: ClientReadableStream\u003cResponse\u003e = client.createServerStreaming(reqBody, reqBody2)\n\n  stream.on('data', (response: Response): void =\u003e {\n    console.log(response.toObject())\n  })\n  ```\n\n+ ### Bindirectional Streaming RPC\n\nadalah sebuah konsep rpc yang dimana client dapat mengirim sebuah request kesisi server lebih dari 1x dalam 1 waktu secara berurutan seperti `Contoh Client Request Support 2` dan sisi server juga dapat mengirim sebuah response lebih dari 1x dalam 1 waktu secara berurutan seperti `Contoh Server Response Support 2`, dikarenakan client dan server menggunakan event streaming untuk mengirim sebuah request dan response baik itu ke sisi client atau server.\n\n\n  ##### Contoh Client Request Support\n\n  ```ts\nconst stream: ClientDuplexStream\u003cUser, Response\u003e = client.createBidirectionalStreaming()\n\n//  get response from server, after server received data from client\nstream.on('data', (response: Response) =\u003e {\n\tconsole.log(response.toObject())\n})\n\n// set request from sending data into server from client\nconst reqBody = new User()\nreqBody.setId(1)\nreqBody.setName('jane doe')\nreqBody.setAge(28)\n\n// send data from client into server\nstream.write(reqBody)\nstream.end()\n```\n\n  ##### Contoh Client Request Support 2\n\n  ```ts\n  const stream: ClientDuplexStream\u003cUser, Response\u003e = client.createBidirectionalStreaming()\n\n  //  get response from server, after server received data from client\n  stream.on('data', (response: Response) =\u003e {\n    console.log(response.toObject())\n  })\n\n  // set request from sending data into server from client\n  const reqBody = new User()\n  reqBody.setId(1)\n  reqBody.setName('jane doe')\n  reqBody.setAge(28)\n\n  const reqBody2 = new User()\n  reqBody2.setId(2)\n  reqBody2.setName('john doe')\n  reqBody2.setAge(30)\n\n  // send data from client into server\n  stream.write(reqBody)\n  stream.write(reqBody2)\n  stream.end()\n  ```\n\n  ##### Contoh Server Response Support\n\n  ```ts\n  export function createBidirectionalStreaming(stream: ServerDuplexStream\u003cUser, Response | ServerErrorResponse\u003e) {\n    const res: InstanceType\u003ctypeof Response\u003e = new Response()\n\n    stream.on('data', (chunk: User) =\u003e {\n      if (!chunk.toObject()) {\n        // set response and send error into client, after server received request body from client\n        const res: InstanceType\u003ctypeof Response\u003e = new Response()\n        res.setStatCode(400)\n        res.setStatMsg('Create new user failed')\n\n        stream.write(res)\n        stream.end(res)\n      }\n\n      console.log(`BidirectionalStreaming:${new Date().toISOString()} - Request body from client: `, chunk.toObject())\n    })\n\n    // set response and sending success into client, after server received request body from client\n    res.setStatCode(200)\n    res.setStatMsg('Create new user successfully')\n\n    stream.write(res)\n    stream.end()\n  }\n  ```\n\n##### Contoh Server Response Support 2\n\n  ```ts\n  export function createBidirectionalStreaming(stream: ServerDuplexStream\u003cUser, Response | ServerErrorResponse\u003e) {\n    const res: InstanceType\u003ctypeof Response\u003e = new Response()\n\n    stream.on('data', (chunk: User) =\u003e {\n      if (!chunk.toObject()) {\n        // set response and send error into client, after server received request body from client\n        const res: InstanceType\u003ctypeof Response\u003e = new Response()\n        res.setStatCode(400)\n        res.setStatMsg('Create new user failed')\n\n        stream.write(res)\n        stream.end(res)\n      }\n\n      console.log(`BidirectionalStreaming:${new Date().toISOString()} - Request body from client: `, chunk.toObject())\n    })\n\n    // set response and sending success into client, after server received request body from client\n    res.setStatCode(200)\n    res.setStatMsg('Create new user successfully')\n    stream.write(res)\n\n    res.setStatCode(200)\n    res.setStatMsg('Create new user successfully2')\n    stream.write(res)\n\n    stream.end()\n  }\n  ```\n\n## Transform GRPC Response\n\njika anda ingin menampilkan data ke format array, anda harus mentransform data tersebut terlebih dahulu, kurang lebih caranya itu seperti ini jika anda menggunakan node.js\n\n+ Server Response\n\n```ts\nfunction transfromRequest({ id, age, name }: User.AsObject): User {\n\tconst user = new User()\n\tuser.setId(id)\n\tuser.setName(name)\n\tuser.setAge(age)\n\n\treturn user\n}\n\nconst users: User[] = [\n  { id: 1, name: 'Jane Doe', age: 28 }\n\t{ id: 2, name: 'John Doe', age: 30 },\n].map(transfromRequest)\n\nexport function resultsUnary(call: ServerUnaryCall\u003cEmpty, Empty\u003e, callback: sendUnaryData\u003cUserList\u003e): void {\n\t// set response and send data into client\n\tconst setUserList = new UserList()\n\tsetUserList.setUsersList(users)\n\n\tcallback(null, setUserList)\n}\n```\n\n+ Client Response\n\n```ts\n// get response from server\nclient.resultsUnary(new Empty(), (err: ServiceError, response: UserList): void =\u003e {\n\tif (err) console.error('Error: ', err)\n\tconsole.log(response.toObject().usersList)\n})\n```\n\n## Important Before Use GRPC\n\n1. dibutuhkan fundamental konsep terkait grpc\n2. dibutuhkan fundamental konsep terkait protobuffer\n3. dibutuhkan pengetahuan terkait bahasa pemerograman apa yang akan digunakan\n4. jika grpc server atau client tidak menggunakan remote method yang di daftarkan di protofile, maka yang terjadi adalah client atau server tidak dapat saling mengirim request atau response.\n5. jika grpc server atau client mati, maka yang terjadi adalah client atau server tidak dapat saling mengirim request atau response, dikarenakan server atau client crash.\n6. jika grpc server atau client berbeda port, maka yang terjadi adalah client atau server tidak dapat saling mengirim request dan response, dikarenakan tidak saling terhubung satu sama lain.\n\n## Example Code\n\n+ [go microservices](https://github.com/restuwahyu13/go-microservices)\n+ [express grpc](https://github.com/restuwahyu13/express-grpc-rest-api)","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frestuwahyu13%2Fnode-grpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frestuwahyu13%2Fnode-grpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frestuwahyu13%2Fnode-grpc/lists"}