gRPC: Google Remote Procedure Call is a Google-developed open-source framework. The gRPC lets you define REQUEST AND RESPONSE for Remote Procedure Call and lessens your struggle by handling the rest. Features of gRPC:
We all know how popular and successful NodeJs is. So, in this tutorial, we will implement gRPC services in NodeJs. We will build a demo application and perform a CRUD operation. So without further ado let’s get started with the implementation of gRPC services in our NodeJS application.
Bacancy will lessen your development struggles. Trust the best! Trust us!
Get in touch with Bacancy, if you are looking for potential NodeJS developers for your dream project. We have highly skilled developers with great problem-solving approaches. Don’t think much! Just contact us and hire NodeJs developer from us!
grpc: It will install the gRPC server
/proto-loader: It will load protobuf file
uuid: It will create random hash ids for students
Now, create students.proto, server.js, and client.js files. A single student item will have- id, name, age, and coursename.
syntax = "proto3"; message Student { string id = 1; string name = 2; int32 age = 3; string CourseName = 4; }
The Students defines our students request message format, where each news request has a unique id, name of the students, age of the students, and course name taken by students.
Create an RPC service. All CRUD operations will be available in this service named StudentsService.
... service StudentsService { rpc GetAllStudents (Empty) returns (NewsList) {} } message Empty {} message StudentsList { repeated Students students = 1; }
The entire code of news.proto file is shown below.
syntax = "proto3"; service StudentService { rpc GetAllNews (Empty) returns (NewsList) {} } message Student { string id = 1; string name = 2; int32 age = 3; string CourseName = 4; } message Empty {} message StudentsList { repeated Student students = 1; } const grpc = require("@grpc/grpc-js"); const PROTO_PATH = "./news.proto"; var protoLoader = require("@grpc/proto-loader"); const options = { longs: String, oneofs: true, keepCase: true, enums: String, defaults: true, }; var packageDefinition =protoLoader.loadSync(PROTO_PATH, options); const newsProto=grpc.loadPackageDefinition(packageDefinition); const {v4:uuidv4}=require(“uuid”) const server = new grpc.Server(); let Students = [ { id: "a68b823c-7ca6-44bc-b721-fb4d5312cafc", name: "John Bolton", age: 22, courseName: "Course 1" }, { id: "34415c7c-f82d-4e44-88ca-ae2a1aaa92b7", name: "John Bolton", age: 22, courseName: "Course 2" }, ]; server.addService(StudentsProto.StudentService.service, { getAll: (_, callback) => { callback(null, {Students}); }, }); server.bind("127.0.0.1:30043",grpc.ServerCredentials.createInsecure()); console.log("Server running at http://127.0.0.1:50051"); server.start();
First of all, we have imported @grpc/grpc-js and @grpc/proto-loader libraries. The const variable named PROTO PATH will save the location of students.proto file. Later, loadSync method will load the proto file into gRPC. And loadPackageDefinition method will load the package definition. After that, to initialize the server instance () we will call new grpc.server
We will call the getAll method defined in Server’s addService method as the second parameter from the client, as shown below.
const PROTO_PATH = "./students.proto"; const grpc = require("@grpc/grpc-js"); var protoLoader = require("@grpc/proto-loader"); var packageDefinition=protoLoader.loadSync(PROTO_PATH, { longs: String, oneofs: true, keepCase: true, enums: String, defaults: true, }); const StudentService = grpc.loadPackageDefinition(packageDefinition).StudentService; const client = new StudentService( "localhost:30043", grpc.credentials.createInsecure() );
Call the getAll method in the server from the client variable.
... const client = new Service( "localhost:30043", grpc.credentials.createInsecure() ); client.getAll(null, (err, data) => { if (!err) throw err console.log(data); });
Now execute the client.js code as follows:
// node client.js { Students: [ { id: "a68b823c-7ca6-44bc-b721-fb4d5312cafc", name: "John Bolton", age: 22, courseName: "Course 1" }, { id: "34415c7c-f82d-4e44-88ca-ae2a1aaa92b7", name: "John Bolton", age: 22, courseName: "Course 2" }, ] }
We have successfully executed a gRPC service method from a gRPC client. After exporting the NewsService instance you can import it in another file for calling methods.
const PROTO_PATH = "./students.proto"; const grpc = require("@grpc/grpc-js"); var protoLoader = require("@grpc/proto-loader"); var packageDefinition=protoLoader.loadSync(PROTO_PATH, { longs: String, oneofs: true, keepCase: true, enums: String, defaults: true, }); const StudentService = grpc.loadPackageDefinition(packageDefinition).StudentService; const client = new StudentService( "localhost:30043", grpc.credentials.createInsecure() ); module.exports = client;
We may now import the client into a different file. We’ll make a separate file for each step we wish to take. We’ll make a file called get test.js that imports the client and calls the getAll method.
// test.js const client = require("./client"); client.getAll(null, (err, data) => { if (!err) throw err console.log(data); });
For inserting data create a new method. Open the proto file and under services, you can add an RPC with the name of the new method. Here, the name of our method is Insert under StudentService service as shown below.
... service StudentService { rpc GetAll (Empty) returns (StudentList) {} rpc Insert (Student) returns (Student) {} } ...
The service will accept the Student message and return the new Student object.
... server.addService(StudentsProto.StudentService.service, { getAll: (_, callback) => { callback(null, {Students}); }, insert: (call, callback) => { let Student = call.request; Student.id = uuidv4(); Students.push(Student); callback(null, news); }, }); ...
Now, we will code for deleting a Student. Here’s the code snippet for the same.
... service StudentService { rpc GetAll (Empty) returns (StudentList) {} rpc Insert (Student) returns (Student) {} rpc Remove (Student) returns (Student) {} } message StudentRequestId { string id = 1; } ...
Here, the request is StudentRequestId which will respond with an empty message.
The code snippet from server.js is shown below.
... remove: (call, callback) => { let existingStudentIndex = Students.findnidex( n =>n.id == call.request.id ); If(existingStudentIndex != -1){ Students.splice(existingStudentIndex,1) callback(null,{}); } }, ...
To update the data we will add a method in the proto file.
... service StudentService { rpc GetAll (Empty) returns (StudentList) {} rpc Insert (Student) returns (Student) {} rpc Remove (Student) returns (Student) {} rpc Update (Student) returns (Student) {} } ...
The method is accepting a Student message and responding with the edited News object. The code for updating the student data is shown below.
... update: (call, callback) => { let existingStudent = Students.find(n=> n.id== call.request.id); if(existingStudent){ existingStudent.name = call.request.name; existingStudent.age = call.request.age; existingStudent.CourseName =call.request.CourseName; callback(null, existingStudent); }, ...
Let’s set a method in the proto file:
... service StudentService { rpc GetAll (Empty) returns (StudentList) {} rpc Get (Student) returns (Student) {} rpc Insert (Student) returns (Student) {} rpc Remove (Student) returns (Student) {} rpc Update (Student) returns (Student) {} } ...
The Get method requires an ID as the request message and returns a Student message. Here’s the implementation in the server.js file:
... get: (call, callback) => { let Student = Students.find(n=>n.id == call.request.id) if(Student) = { callback(null, Student); } }, ...
We get the id from the call param object. The id is used to retrieve the corresponding student item from the Students array. The callback function is called with the retrieved student item passed as param, this makes the client gets the student item.
// test.js // get all news const client = require("./client"); client.getAll({}, (error, students) => { if (error) throw error; console.log(students); }); //add a students client.insert( { name: "Title news 3", age: 11, CourseName: "Image URL here", }, (err, students) => { if (err) throw err; console.log("Successfully created a students."); } ); // edit a student client.update( { id: "a68b823c-7ca6-44bc-b721-fb4d5312cafc", name: "Title news 3", age: 11, CourseName: "Image URL here", }, (err, students) => { if (err) throw err; console.log("Successfully Updated a Students."); } ); // delete a students client.remove( { id: "34415c7c-f82d-4e44-88ca-ae2a1aaa92b7", }, (err, students) => { if (err) throw err; console.log("Successfully deleted students record."); } );
Now, run the file:
We now have a server, proto, and client all built and ready. Attach a Node server to the client.js so an endpoint in our server will call the procedure in the gRPC news service. Here are the endpoints.
Here’s the code in Nodejs:
const client = require("./client"); const express = require("express"); const bodyParser = require("body-parser"); const app = express(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.get("/", (req, res) => { client.getAll(null, (err, data) => { if (!err) { res.send(data.Students) } }); }); app.post("/save", (req, res) => { console.log(req.body.CourseName) let newStudent = { name: req.body.name, age: req.body.age, CourseName: req.body.CourseName }; client.insert(newStudent, (err, data) => { if (err) throw err; res.send({data:data, msg:"Student created successfully"}) }); }); app.post("/update", (req, res) => { const updateStudent = { id: req.body.id, name: req.body.name, age: req.body.age, CourseName: req.body.CourseName }; client.update(updateStudent, (err, data) => { if (err) throw err; res.send({msg:"Student updated successfully"}) }); }); app.post("/remove", (req, res) => { client.remove({ id: req.body.Student_id }, (err, _) => { if (err) throw err; console.log("Student removed successfully"); //res.redirect("/"); res.send({msg:"Student removed successfully"}) }); }); const PORT = 3000; app.listen(PORT, () => { console.log("Server running at port %d", PORT); });
So, this was about how can we implement gRPC services in NodeJS. I hope your purpose of landing on this tutorial has served you well. If you are a NodeJS enthusiast then feel free to visit the NodeJS tutorials page and learn more about Node. We are always open to suggestions and feedback. Write us back if you have any questions. Bacancy has best NodeJS developers with basic and advanced knowledge; contact us to hire NodeJs developers for your application.
Your Success Is Guaranteed !
We accelerate the release of digital product and guaranteed their success
We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.