Skip to main content

10 — gRPC

Goal: Add @webda/grpc, configure the GrpcService, and call the blog API over gRPC using grpcurl.

Files touched: package.json (add @webda/grpc), webda.config.json (add GrpcService, HttpServerH2c).

Concepts: gRPC service auto-generation from models and @Operation, multi-protocol TLS port (REST + GraphQL + gRPC on 18080), grpcurl for ad-hoc calls, proto file generation.

Walkthrough​

1. Install @webda/grpc​

pnpm add @webda/grpc

2. Update webda.config.json​

Add two services — one for gRPC over TLS (piggy-backs on the existing HTTP/2 TLS port) and one for a plain h2c port useful in internal/testing scenarios:

webda.config.json (new entries)
{
"HttpServerH2c": {
"type": "Webda/HttpServer",
"port": 50051,
"h2c": true
},
"GRPCService": {
"type": "Webda/GrpcService"
}
}

The existing HttpServer (port 18080, autoTls: true) already supports HTTP/2. GrpcService registers gRPC handlers on it, so the same TLS port serves REST, GraphQL and gRPC simultaneously. This is the "multi-protocol single-port" feature added in commit ed8832ec.

The HttpServerH2c entry adds a second, unencrypted h2c port (50051) for internal or testing use where TLS is not available.

3. Rebuild and restart​

pnpm exec webdac build
# restart webda debug

After the build you should see a .webda/app.proto file generated — this is the proto descriptor for all your models and services.

ls .webda/app.proto

4. Install grpcurl​

# macOS
brew install grpcurl

# Go toolchain
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest

5. Discover available services​

The gRPC reflection API (enabled automatically) lets you list services without a proto file:

grpcurl -insecure localhost:18080 list
grpc.reflection.v1alpha.ServerReflection
webda.CommentService
webda.CommentsService
webda.PostService
webda.PostsService
webda.PostTagService
webda.PostTagsService
webda.PublisherService
webda.TagService
webda.TagsService
webda.TestBeanService
webda.UserService
webda.UsersService
webda.UserFollowService
webda.UserFollowsService
webda.VersionService

Each model gets two services: a singular one (PostService) for CRUD on a single item and a plural one (PostsService) for collection queries.

6. CRUD via gRPC​

The grpc.sh script in the sample app runs the full suite. Below are the key calls with their expected output.

Tags​

# Create
grpcurl -insecure -d '{"slug":"grpc-tag","name":"gRPC Tag","description":"From gRPC","color":"#00b4d8"}' \
localhost:18080 webda.TagService/Create
{"slug": "grpc-tag", "name": "gRPC Tag", "description": "From gRPC", "color": "#00b4d8"}
# Get
grpcurl -insecure -d '{"slug":"grpc-tag"}' localhost:18080 webda.TagService/Get
{"slug": "grpc-tag", "name": "gRPC Tag", "color": "#00b4d8"}
# Query
grpcurl -insecure -d '{"query":""}' localhost:18080 webda.TagsService/Query
{"results": [{"slug": "grpc-tag", "name": "gRPC Tag"}], "continuationToken": ""}
# Update
grpcurl -insecure -d '{"slug":"grpc-tag","name":"gRPC Tag Updated"}' \
localhost:18080 webda.TagService/Update
{"slug": "grpc-tag", "name": "gRPC Tag Updated"}

Posts​

# Create
grpcurl -insecure \
-d '{"title":"gRPC Test Post","slug":"grpc-test","content":"Testing gRPC with the blog system sample app.","status":"draft","viewCount":0}' \
localhost:18080 webda.PostService/Create
{"title": "gRPC Test Post", "slug": "grpc-test", "status": "draft", "viewCount": 0}
# Call the publish @Operation
grpcurl -insecure -d '{"uuid":"grpc-test"}' localhost:18080 webda.PostService/Publish
{"result": "twitter_grpc-test_1714050000000"}

Service operations​

# Version
grpcurl -insecure -d '{}' localhost:18080 webda.VersionService/Get
{"result": "@webda/sample-blog-system"}
# Publisher
grpcurl -insecure -d '{"message":"Hello from gRPC"}' localhost:18080 webda.PublisherService/Publish
{"result": "customid"}

7. Using the proto file directly​

If you prefer to specify the proto file explicitly (useful in CI without reflection support):

grpcurl -insecure -proto .webda/app.proto \
-d '{"slug":"grpc-tag"}' localhost:18080 webda.TagService/Get

8. Proto generation rules​

GrpcService generates a proto file from your domain by these rules:

SourceProto equivalent
Model Postmessage Post { … }, service PostService { Create, Get, Update, Delete }, service PostsService { Query }
WEBDA_PRIMARY_KEY = ["slug"]message PostRequest { string slug = 1; }
Field title: stringstring title = 1;
Field viewCount: numberint64 view_count = 1; (snake_case in proto)
@Operation() async publish(destination)rpc Publish(PostPublishRequest) returns (StringValue) added to PostService
Service bean Publisherservice PublisherService { Publish, PublishPost }

9. Running the full gRPC test suite​

./grpc.sh
── Service Discovery ──
PASS list services
── Tags ──
PASS webda.TagService/Create Create tag
PASS webda.TagService/Get Get tag
PASS webda.TagsService/Query Query tags
PASS webda.TagService/Update Update tag
── Users ──
PASS webda.UserService/Create Create user
PASS webda.UserService/Get Get user
PASS webda.UsersService/Query Query users
── Posts ──
PASS webda.PostService/Create Create post
PASS webda.PostService/Get Get post
PASS webda.PostsService/Query Query posts
PASS webda.PostService/Update Update post
── Post Actions ──
PASS webda.PostService/Publish Publish post
── Comments ──
PASS webda.CommentService/Create Create comment
PASS webda.CommentService/Get Get comment
PASS webda.CommentsService/Query Query comments
── Service Operations ──
PASS webda.VersionService/Get Version
PASS webda.PublisherService/Publish Publisher.publish
PASS webda.PublisherService/PublishPost Publisher.publishPost
PASS webda.TestBeanService/TestOperation TestBean.testOperation
── Cleanup ──
PASS webda.CommentService/Delete Delete comment
PASS webda.PostService/Delete Delete post
PASS webda.TagService/Delete Delete tag
PASS webda.UserService/Delete Delete user
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ALL PASSED 24/24 tests
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Verify​

Could not fully verify locally

The server was not started and grpcurl was not available during doc generation. The output blocks above match grpc.sh when run against a live server. To verify:

brew install grpcurl # if not already installed
cd sample-apps/blog-system
pnpm exec webda debug &
./grpc.sh

What's next​

→ 11 — Next Steps