Search code examples
c#next.jsgrpchttp2grpc-web

How can I call gRPC endpoint from Next.js Application inside of a functional component?


I have set up default gRPC server via Visual Studio .net 6.0.

The proto file is as foolowing:

syntax = "proto3";

option csharp_namespace = "GrpcService";

package greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

And the Greeter service as following:

using Grpc.Core;

namespace GrpcService.Services
{
    public class GreeterService : Greeter.GreeterBase
    {
        private readonly ILogger<GreeterService> _logger;
        public GreeterService(ILogger<GreeterService> logger)
        {
            _logger = logger;
        }

        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        {
            return Task.FromResult(new HelloReply
            {
                Message = "Hello " + request.Name
            });
        }
    }
}

So the default one, nothing fancy. I know how to call this service via C#. And I get back the result as per the function above.

I though don't understand what packages and how should I call it from a web app client via javascript, in a next.js component.

I want to achieve that on a click [for example] I will be calling this.

import type { NextPage } from "next";
import styles from "../styles/Home.module.css";

const Home: NextPage = () => {
  const grpcCall = () => {
    try {
      const grpc = require("grpc");
      const protoLoader = require("@grpc/proto-loader");
      const packageDef = protoLoader.loadSync("greet.proto", {});
      const grpcObject = grpc.loadPackageDefinition(packageDef);
      const greetPackage = grpcObject.greet;
      const client = new greetPackage.Greeter(
        "https://localhost:49153/",
        grpc.credentials.createInsecure()
      );
      client.SayHello({ name: "Say Hello" });
    } catch (error) {
      console.log(error);
    }
  };

  return (
    <div className={styles.container}>
      <div onClick={grpcCall} className={styles.title}>
        Press to call gRPC HERE
      </div>
    </div>
  );
};

export default Home;

The above code though complains about fs not being resolved, though I don't really think it is the issue.

Error:

Module not found: Can't resolve 'fs'

Import trace for requested module:
./node_modules/@grpc/proto-loader/build/src/index.js
./pages/index.tsx

https://nextjs.org/docs/messages/module-not-found
Could not find files for / in .next/build-manifest.json
Could not find files for / in .next/build-manifest.json

And the whole project is a default next.js app with typescript setting.

So the question is How do I do the call from a javascript client to C# server via gRPC? What code should I add here?

I would apprieciete a simple solution here and if possible detailed explanation.

Regards,


Solution

  • All you have to do is just share the proto files with the client. For example:

    const grpc = require('@grpc/grpc-js');
    const protoLoader = require('@grpc/proto-loader');
    
    const PROTO_PATH = __dirname + '/Protos/greet.proto';
    
    
    const pd = protoLoader.loadSync(PROTO_PATH);
    const GreeterService = grpc.loadPackageDefinition(pd).greet.Greeter;
    
    
    // Point your remote server instead of localhost:5043 also, update your credentials. 
    
    const client = new GreeterService("localhost:5043", grpc.credentials.createInsecure());
    client.sayHello({ name: "Sajan" }, (err, response) => {
        if(err) {
            return console.error(err);
        }
        console.log(`Message received from dotnet grpc: ${response.message}`);
    });
    
    

    output:

    enter image description here