Guide to integrating NextJS with gRPC and NestJS via HTTP/2
Introduction
- gRPC is a high-performance RPC (Remote Procedure Call) framework developed by Google, using Protocol Buffers (protobuf) as the interface definition language and data serialization format. Unlike traditional REST which uses text (JSON), gRPC transmits data in binary format to optimize payload size and processing speed. In particular, gRPC operates based on HTTP/2, providing outstanding advantages such as: Multi-plexing (sending multiple concurrent requests over a single connection), Header Compression, and Server Push, helping to reduce latency and increase bandwidth for microservices systems.
- In this article, I will use NextJS for the frontend and act as a BFF (Backend For Frontend) as a proxy server to aggregate information and communicate via HTTP/2 gRPC with the NestJS server.
- Our connection will be as follows: Frontend connects to NextJS proxy server using restful api HTTP/1.1, NextJS connects to NestJS using gRPC via HTTP/2, we need a NextJS middleware to handle it, not direct connection from frontend to NestJS using gRPC, to avoid returning proto config file information to the frontend side, enhancing security, hiding server information and simplifying handling for the frontend side.
Prerequisites
First, you need some basic knowledge about NextJS and NestJS including project creation, please see previous articles to know how to create NextJS and NestJS projects before continuing.
Detail
General Setup
The following config information is related to the proto file used for gRPC communication between NextJS proxy and NestJS server, please do the same for both projects including the following steps (in reality you could create a sub repository to share proto file between projects):
First, install the following packages
- bufbuild/buf/buf: This is a command-line tool (CLI) that serves as a modern replacement for the traditional protoc compiler. It helps you manage .proto files, perform linting, detect breaking changes (to ensure backward compatibility), and efficiently handle code generation.
- Code Generation (Development Dependencies): these are used only during development to transform .proto files into .ts or .js files.
- @bufbuild/buf: The Node.js distribution of the Buf CLI, allowing you to run Buf commands directly via npx or scripts within your package.json.
- @bufbuild/protoc-gen-es: A plugin used to generate data structures (Messages) and metadata from Protobuf files into ECMAScript (TypeScript/JavaScript).
- @connectrpc/protoc-gen-connect-es: A plugin used to generate service interfaces for both clients and servers based on the Connect protocol.
- Runtime Libraries (Dependencies): these libraries run directly within your application code.
- @connectrpc/connect: The core library that enables you to write request handlers for services and invoke APIs (Clients). It supports the gRPC, gRPC-Web, and Connect protocols.
- @connectrpc/connect-node: Provides specific adapters to run Connect within the Node.js environment (supporting both HTTP and HTTP/2).
- @bufbuild/protobuf: The runtime library responsible for handling the serialization and deserialization of Protobuf objects in JavaScript/TypeScript.
Create file proto/aggregator.proto
The above code defines the data structure and gRPC services using Protocol Buffers. It defines AggregatorService with 3 methods (RPC): GetPrice, GetNews, and GetSocial. Each method specifies the input data type (IdRequest) and corresponding output, helping to ensure consistency in data types between Client (NextJS) and Server (NestJS).
Create file buf.gen.yaml
This file is the configuration for the buf tool to automatically generate TypeScript source code from the .proto file. The es plugin is responsible for creating message definitions (messages), while the connect-es plugin creates service and client definitions to be able to call gRPC methods easily in a TypeScript environment.
Add the following command to the package.json file
After executing the command, files will be created in the gen folder as follows:
NestJS Project
Install the following packages
Since NestJS uses Express by default which does not support HTTP/2, we have to switch to using Fastify which supports HTTP/2.
Create file service/coin.service.ts
This is where the main business logic is handled on the Backend side. It contains methods for calculating simulated prices, getting random news, and social media metrics based on the coin code (ID).
Create file router/coin.routes.ts
This code performs mapping between gRPC service definition (AggregatorService) with actual logic in CoinService. It registers RPC methods with ConnectRouter, specifying that when a gRPC request arrives, it will call the corresponding function in CoinService to return results to the client.
Create file router/grpc.router.ts
This file sets up a middleware for NestJS using connectNodeAdapter. Its task is to check incoming requests; if the request has a path starting with the gRPC namespace (/aggregator.v1.), it will redirect that request to the gRPC handler for processing. Otherwise, it will ignore it so that traditional NestJS REST routes can receive it.
Update file main.ts
This is the NestJS application initialization file. The important point is the use of FastifyAdapter with configuration HTTP/2: true, allowing the server to support the HTTP/2 protocol. It then calls grpcRouter(app) to register the previously configured gRPC routes into the application lifecycle.
Update file app.module.ts
NextJS Project
Create .env file
Create file app/_lib/grpc-client.ts
This code snippet initializes a gRPC Client on the NextJS side. It uses createConnectTransport to establish a connection to the NestJS Server (running on port 4000) via the HTTP/2 protocol. grpcClient then provides type-safe functions to call Backend like a normal local function.
Create file app/api/coin-summary/[id]/route.ts
This is an API Route in NextJS acting as a BFF. It receives requests from the Frontend, then performs concurrent calls to 3 different gRPC services via Promise.allSettled. This technique helps aggregate data from multiple sources quickly and safely: if one service fails or times out, the rest can still return data to the user instead of breaking the entire request.
Create file app/coin/page.tsx
This Dashboard page allows selecting a cryptocurrency from a list. When users change their selection, the page calls NextJS's internal API, receives aggregated data from gRPC, and visually displays price information and market news.
Result as follows
When checking NestJS server logs, you will see the protocol is HTTP/2
Happy coding!
Comments
Post a Comment