If you have been reading about gRPC for a while, but haven’t gotten around to check it out, this is your short cut guide to using gRPC in Aurelia 2!

I think gRPC is looking promising on paper. It’s still early days and both browsers, as well as Azure services I use, doesn’t support all features of it yet. However, knowledge is an easy burden, so I thought I’d at least check it out and see how to use it from the web in a Aurelia 2 SPA 😁

🥞Aurelia2 Web Client – .NET Back-end

The Project consists of a web client using au2. As for server I decided to try gRPC support of .NET, so the back-end is a .NET 5 project.

There is a gRPC Service template available in Visual Studio. I use VS2019 Community Preview Edition, this allowed me to select .NET 5 as a framework.

As for the Web Client project, that’s just a regular Aurelia 2 project created from a CLI.

The data used is slightly more complex than all starter scenarios I’ve seen, where the reply is just a string. I wanted to try it with more complex objects and see if it was still as easy. Spoiler alert: it wasn’t 😩

🤖gRPC protobuf

If you are new to gRPC: the word protobuf is short for protocol buffer language and is a way to describe services and types. To work with these files, there is a compiler available with multiple plugins. The compiler and the plugins are used to generate data access classes from your .proto files.

The .proto file used in this demo can be seen below.

syntax = "proto3";

option csharp_namespace = "GrpcNETService.Generated";

service DroidService {
  rpc GetAll (DroidsRequest) returns (DroidsReply);
}

message DroidsRequest { }

message DroidsReply {
  repeated Droid droids = 1;
}

message Droid {
  repeated string armament = 1;
  string class = 2;
  repeated string equipment = 3;
  int32 height = 4;
  string manufacturer = 5;
  string model = 6;
  repeated string plating_color = 7;
  int32 price = 8;
  repeated string sensor_color = 9;
}

This .proto file defines a service, an rpc call named GetAll. It also defines the the request and response types used to call that service.
Last but not least, the definitions of our Droid type, that we will try to work with in the front-end project.

🧾Back-end .NET 5 gRPC c# Project Setup

First off create a new project from the gRPC project template in Visual Studio. I use Visual Studio 2019 Community Edition.

✅Installing prerequisites

There’s one dependency we need to install to get gRPC for Web working, just run the following from the Package Manager Console:

Install-Package Grpc.AspNetCore.Web

👩‍🔧Compiling .proto files with Visual Studio

Luckily the gRPC project in .NET is setup to compile .proto files for you! I tried doing this from the command line at first. Reason was I wanted to run one command to compile all .proto files for both projects at the same time. Turned out the c# experience was not as smooth as I hoped for with a command line solution.

However, the Visual Studio gRPC project template re-compiles the .proto files on every build. That solution is good enough and avoids the generated code becoming out of sync for the .NET project!

I solved sharing the .proto files between the back-end and front-end projects by putting a “protos” folder in the root of the directory, holding all .proto files. But for VS2019 to find the files, we need to modify the csproj-file and add a new ItemGroup👇.

<ItemGroup>
	<Protobuf Include="../protos/*.proto" GrpcServices="Server" OutputDir="%(RelativePath)Services" CompileOutputs="false" />
</ItemGroup>

This will help Visual Studio to find the protos directory in the root and it will output the compiled files into the Services folder inside the project. The option GrpcServices="Server" tells the compiler we are only needed in compiling protobuf files needed to host a gRPC server.

👨‍🏭Making it work

There’s a few steps needed to startup.cs to make the c# project work.

  1. Nuget – reference gRPC and gRPC Web
  2. Setup and use CORS
  3. Add the gRPC endpoint for our service
public class Startup
    {
        const string ERROR_REPLY = "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909";

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddGrpc();
            services.AddCors(o => o.AddPolicy("AllowAll", builder =>
            {
                builder.AllowAnyOrigin()
                       .AllowAnyMethod()
                       .AllowAnyHeader()
                       .WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding");
            }));

            List<Droid> droids = FakeDroidStore.GetAllDroids();
            services.AddSingleton(droids);
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();
            app.UseGrpcWeb();
            app.UseCors();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGrpcService<DroidService>().EnableGrpcWeb().RequireCors("AllowAll");
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync(ERROR_REPLY);
                });
            });
        }
    }

I also added a collection of items from a fake store to the DI container. This is just a test – don’t do that in production code! 😁

🧾Front-end Aurelia 2 Project Setup

The Aurelia 2 project was setup by running (Node is needed to be able to use npx):

npx au2 new

Then I choose the following settings:

au2 project setup
Aurelia 2 Project Setup

✅Installing prerequisites

To work with protobuf files and compile the web-shims you need to install some files. Get the following and make sure they are accessible in your path (on Windows):

  1. protoc
  2. grpc-web

👩‍🔧Compiling .proto files from the command line

Compiling the proto files for the web project was made with the protoc compiler from the command line.

For ease of use in or project the grpc-web output is in TypeScript.
⚠ this is still a beta feature and might have issues.

Position in the root/protos directory and run the following. (It should be on the same line!)

protoc droids.proto --js_out=import_style=commonjs:../web-client/src/proto/gen --grpc-web_out=import_style=typescript,mode=grpcwebtext:../web-client/src/proto/gen

This will compile the protobuf and put the generated files inside the web project in the folder web-client/src/proto/gen.

👨‍🏭Making it work

Calling the gRPC Service is quite forward. First instantiate a ServiceClient, then a service Request. Then call the service using the request.

    const client = new DroidServiceClient("https://localhost:5001");
    const request = new DroidsRequest();

Note, in the proto file, the name of the service is GetAll. This is converted to getAll following JS standards. The return type however looks like follows:

message DroidsReply {
  repeated Droid droids = 1;
}

The repeated keyword indicates that the field is a collection of values. This will lead to the the type being suffixed with List and accessible as droidsList.

There’s two ways to work with the reply type. One is getting the droidsList type from the response. Then when binding to that in the view, we use getters created on the type, for ex (and here we see another repeated property getting the List suffix):

  <div>Plating colors available is ${droid.getPlatingColorList()}</div>

Another way is to use the toObject method on the response and get the “raw” droidsList from that.

  this.droids = response.toObject().droidsList;

This enables us to bind to the view without referring to methods, which perhaps feels more “Aurelia native”. Do note below that the reserved word class is changed to pb_class 👍

 <div>Class: ${droid.pb_class}</div>

🧱Using JavaScript Files in our TypeScript Project

Since one of the files from the generated protobuf code is a .js file, we need to tell the ts compiler to allow .js files as well. Modify the tsconfig and add the compiler option:

"allowJs": true

If using dumber to build and bundle the project, then modify gulpfile.js and add a step to include js files in the build, see line 137 👇

function build() {
  // Merge all js/css/html file streams to feed dumber.
  // dumber knows nothing about .ts/.less/.scss/.md files,
  // gulp-* plugins transpiled them into js/css/html before
  // sending to dumber.
  return (
    merge2(
      gulp.src("src/**/*.json"),
      buildJs("src/**/*.ts"),
      buildJs("src/**/*.js"),
      buildHtml("src/**/*.html"),
      buildCss("src/**/*.css")
    )

🎢Running the Project

Build and start the back-end project from Visual Studio 2019. Install npm dependencies and run the front-end project with npm start. The web-client should open in a new browser. After pressing the “Get All Droids” button, if everything works, two lists of droid info will be displayed.

Screenshot showing browser displaying Aurelia SPA with a list of droids from the gRPC web call
Data fetched successfully from the Aurelia SPA via gRPC

🔮Conclusion

The size of the gRPC payload sent to the client is about half the size of the json payload (approx 2kb vs 4kb). So that’s pretty cool! If you are having having huge payloads in your projects, it means there’s lot’s to gain form gRPC.

The developer experience I’d say feels slightly off. Maybe it’s just a case of “who moved my 🧀”? Automating the protobuf compilation in the front-end project as well, making it a build step, would probably help a bit. Using the getters on the reply object also feels slightly off when binding to views in the front-end, but since it’s not necessary to use them I guess that’s ok.

Using the protobuf defined types directly in the back-end project also feels slightly “off”. Would be great to get some feedback from developers actually using gRPC in production if they are using the protobuf defined types, or other abstractions for them?!

Then there is still the issue of native support in browsers and hosting services. In my opinion, the coolest part of gRPC is streaming, and this needs to be sorted to fully enjoy gRPC. However, in some near future, I suspect a lot of web apps will transition to gRPC from using json based API’s.

As for service to service communication, I’d be willing to try out gRPC. Especially if the setup enables streaming, that’d be great for some applications 😃

🔗Resources

Find the code on my github
Read more about gRPC at grpc.io
Aurelia 2 documentation

Using gRPC in Aurelia 2
Tagged on:     

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.