How to Implement gRPC Services in NodeJS?
www.bacancytechnology.com
What is gRPC?
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: Modern Fast Has low latency Efficient Load balancing Supports streaming Plugin authentication Monitors data Build on top of HTTP/2 Lanaguage independent
Tutorial Goal: Implement gRPC services in NodeJS
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!
Steps to Implement gRPC services in NodeJS?
Initialize Node environment npm init -y
Install gRPC server
npm install --save grpc @grpc/proto-loader uuid express body-parser
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.
Define the StudentService in proto 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;
} message Empty {} message StudentsList { repeated Student students = 1; } }; var packageDefinition =protoLoader.loadSync(PROTO_PATH, options); const newsProto=grpc.loadPackageDefinition(pac kageDefinition); 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.StudentSe rvice.service, { getAll: (_, callback) => { callback(null, {Students});
}, }); server.bind("127.0.0.1:30043",grpc.ServerCre dentials.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
Create Client stub 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/protoloader"); var packageDefinition=protoLoader.loadSync(P ROTO_PATH, {
}); const StudentService = grpc.loadPackageDefinition(packageDefiniti on).StudentService; const client = new StudentService( "localhost:30043", grpc.credentials.createInsecure() );
getAll Method: Get all Students 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/protoloader"); var packageDefinition=protoLoader.loadSync(P ROTO_PATH, { longs: String, oneofs: true, keepCase: true, enums: String, defaults: true, }); const StudentService = grpc.loadPackageDefinition(packageDefiniti on).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); });
Insert a Student record 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.StudentSe rvice.service, { getAll: (_, callback) => { callback(null, {Students}); },
insert: (call, callback) => { let Student = call.request; Student.id = uuidv4(); Students.push(Student); callback(null, news); }, }); ...
Delete a Student 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,{}); } }, ...
Update an existing Student 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);
Get a Student 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-b721fb4d5312cafc", 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-88caae2a1aaa92b7", }, (err, students) => { if (err) throw err; console.log("Successfully deleted students record."); } );
Now, run the file: node test
With Http server 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. GET endpoint will call the getAll subroutine to get all the students in the database. /save POST endpoint will call the insert sub-routine to create a new student item.
/update PUT will call the update subroutine to edit/update a student item. /remove DELETE will call the delete sub-routine to delete a student item. 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); });
Conclusion
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.
Thank You
www.bacancytechnology.com