juliaio/grpcclient.jl/grpcclient-jl

Claude Code and agent skill by juliaio/grpcclient.jl

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Call gRPC services from Julia with gRPCClient.jl. Covers generating client stubs from .proto files with protojl, the channel + service-module API (gRPCChannel, Service.RPC calls, gRPCAsync, put!/take!/fetch/wait/iterate/close/detach) and the legacy gRPCServiceClient API, unary and streaming RPC, deadlines and cancellation, bearer tokens and metadata, raw protobuf buffers, and which layer raises which exception. Use when writing, debugging, or reviewing Julia code that touches gRPCClient, gRPCChannel, generated service modules, gRPCAsync, gRPCServiceClient, grpc_sync_request, grpc_async_request, grpc_async_await, grpc_cancel, grpc_init, grpc_register_service_codegen, or generated `*_Client` constructors.

Install

npx vskill@latest install juliaio/grpcclient.jl/grpcclient-jl

SKILL.md

gRPCClient.jl

A Julia gRPC client built on libcurl for HTTP/2 transport, with client stubs generated by ProtoBuf.jl. Version 1.2.0-rc1. Requires Julia 1.10, streaming RPC included.

Exported names: grpc_init, grpc_shutdown, grpc_global_handle, grpc_register_service_codegen, gRPCChannel, gRPCAsync, grpc_async_request, grpc_async_await, grpc_sync_request, grpc_cancel, gRPCCURL, gRPCRequest, gRPCServiceClient, gRPCAsyncChannelResponse, gRPCException, gRPCServiceCallException.

Two APIs

Codegen emits two client APIs, both on by default:

  • Current API (this document): a reusable gRPCChannel plus one baremodule per service, where each RPC is a function called as MyService.MyRPC(chan, request). Prefer it for new code.
  • Legacy API (see Legacy API below and the reference files): generated MyService_MyRPC_Client constructors driven by grpc_sync_request / grpc_async_request / grpc_async_await. Kept for backwards compatibility.

Both are generated from the same .proto. grpc_register_service_codegen(legacy = false) before protojl drops the legacy half, generating less code and giving cleaner IDE completions.

Two rules that silently break everything

  1. `using gRPCClient` must come before `protojl`. Loading the package registers the service codegen hook in __init__. Generate stubs without it loaded and the output contains message structs but no service module or *_Client constructors, with no error to tell you.
  2. Generated files are `include`d, not `using`ed. They are plain scripts, not registered packages.

Generate stubs

julia
using ProtoBuf
using gRPCClient # before protojl, see rule 1
protojl("path/to/service.proto", "proto_search_root", "output_dir")

The arguments are the .proto file, the directory used to resolve its import statements, and the output directory. For package foo, output lands in output_dir/foo/foo_pb.jl with a thin output_dir/foo/foo.jl module wrapper. Read references/codegen.md for the generated layout, the two emitted APIs, the grpc_register_service_codegen switches, cross-package imports, and the proto to Julia type mapping.

Create a channel

A gRPCChannel is a lightweight value holding a handle, host, port, and options. Create one and reuse it for every RPC against that server:

julia
using gRPCClient
include("gen/foo/foo_pb.jl")
chan = gRPCChannel("localhost", 50051; deadline = 30)

Connection options, accepted by gRPCChannel and overridable per call (the per-call value wins):

OptionDefaultNotes
securefalsetrue selects https, false selects http
deadline10Seconds, covering the whole call from submission including time queued for a concurrency slot. Inf disables it. 0 expires immediately; negative, NaN, and -Inf raise INVALID_ARGUMENT
keepalive60Seconds; sets both TCP keepalive idle time and probe interval
max_send_message_length4*1024*1024Per outgoing message, excluding the 5-byte gRPC frame
max_recieve_message_length4*1024*1024Per incoming message. The keyword carries a spelling error, recieve, and must be written exactly that way
tokennothingSent as authorization: Bearer <token> on every request
metadatanothingDict{String,String} of extra headers. Per-call metadata merges key by key with channel metadata rather than replacing it

Any other keyword raises ArgumentError: Invalid field of gRPCConnectionOptions, which is what a misspelling looks like. The grpc handle (which connection pool and concurrency limit to use, see references/concurrency.md) is a keyword too: gRPCChannel("host", 50051; grpc = h).

Setting token and an authorization metadata entry together raises INVALID_ARGUMENT, since they are the same header; the check is case insensitive. To override a channel-level token per call, pass token = nothing next to the new metadata.

grpc_init() runs automatically when the package loads, so no setup call is needed. grpc_shutdown() closes connections and cancels in-flight requests, which is useful under Revise or before exiting.

Calling an RPC

Each service becomes a baremodule; each RPC is an exported function inside it. Pass the channel (or a bare host, port pair) plus the request wherever the request side is unary. How the call is driven depends on the RPC's shape, and only synchronous unary returns the response directly — every other form returns a call handle.

julia
chan = gRPCChannel("localhost", 50051)
# Unary, synchronous: blocks, returns the decoded response, throws on error
response = MyService.MyRPC(chan, MyRequest(42, UInt64[]))
# Bare host/port instead of a channel (builds a one-off channel)
response = MyService.MyRPC("localhost", 50051, MyRequest(42, UInt64[]))
Unary, asynchronous

Pass gRPCAsync() to start the call without blocking; it returns a gRPCUnaryCall. fetch waits for the response (raising on error) and releases resources. fetch does not consume: repeated calls return the same response.

julia
rpc = MyService.MyRPC(chan, MyRequest(42, UInt64[]), gRPCAsync())
# ... other work while the call is in flight ...
response = fetch(rpc)

For many in-flight calls whose responses you want as they land, pass a channel and an index instead:

julia
ch = Channel{gRPCAsyncChannelResponse{MyResponse}}(10)
for (index, request) in enumerate(requests)
MyService.MyRPC(chan, request, ch, index) # returns nothing
end
for _ in 1:length(requests)
cr = take!(ch) # fields: index, response, ex
isnothing(cr.ex) || throw(cr.ex) # a failed call arrives with ex set, response nothing
handle(cr.index, cr.response)
end
Streaming
ShapeOpen withSendReceiveFinish
Client streamingMyService.MyClientStreamRPC(chan)put!(rpc, msg)fetch(rpc) (the single response)fetch closes the request stream for you
Server streamingMyService.MyServerStreamRPC(chan, req)—take!(rpc) / for r in rpcclose(rpc) or detach(rpc)
BidirectionalMyService.MyBidiRPC(chan)put!(rpc, msg)take!(rpc) / for r in rpcput!(rpc; done = true), then close/detach
julia
# Client streaming: many requests, one response
rpc = MyService.MyClientStreamRPC(chan)
for i in 1:100
put!(rpc, MyRequest(i, UInt64[]))
end
response = fetch(rpc) # ends the request stream and returns the response
# Server streaming, known count
rpc = MyService.MyServerStreamRPC(chan, MyRequest(10, UInt64[]))
for _ in 1:10
response = take!(rpc)
end
close(rpc)
# Server / bidirectional streaming, unknown count
for response in rpc # ends cleanly when the server closes the stream
handle(response)
end

Read references/streaming.md before writing streaming code — it covers draining safely, the take!/fetch/wait semantics, and finishing with close vs detach.

Handle operations

Every form except synchronous unary returns an AbstractgRPCCall handle. Supported operations, the shapes that accept them, and when each throws (on failure = only when the call ends with a non-OK status; a clean call never throws there):

OperationApplies toThrows
put!(rpc, msg)client, bidiIf the call has ended
put!(rpc[, msg]; done = true)client, bidiOnly when sending msg
isfull(rpc) (Julia 1.12 or later)client, bidiNever
isopen(rpc)allNever
isready(rpc)allNever
wait(rpc)allOn failure
fetch(rpc)async unary, client, server, bidiOn failure (streaming: when ended and drained)
take!(rpc)server, bidiWhen ended and drained
for r in rpc / iterateserver, bidiOn failure
close(rpc)allOn failure
detach(rpc; throws = true)allOn failure

Raw buffers

Pass Vector{UInt8} in place of a typed message to send an already-encoded payload, or as an extra argument to receive one undecoded. Either side is independent. Works on the call itself and on put! / take! / fetch.

julia
using ProtoBuf
io = IOBuffer(); encode(ProtoEncoder(io), MyRequest(42, UInt64[])); raw = take!(io)
response = MyService.MyRPC(chan, raw) # raw request, typed response
raw_resp = MyService.MyRPC(chan, MyRequest(42, UInt64[]), Vector{UInt8}) # raw response
resp = take!(server_stream_rpc, Vector{UInt8}) # raw streaming response

See references/raw-buffers.md.

Errors

julia
struct gRPCServiceCallException <: gRPCException
grpc_status::Int # gRPC status code
message::String
end

The GRPC_* status constants are not exported. Qualify them (gRPCClient.GRPC_DEADLINE_EXCEEDED) or import them explicitly. Available: GRPC_OK, GRPC_CANCELLED, GRPC_UNKNOWN, GRPC_INVALID_ARGUMENT, GRPC_DEADLINE_EXCEEDED, GRPC_NOT_FOUND, GRPC_ALREADY_EXISTS, GRPC_PERMISSION_DENIED, GRPC_RESOURCE_EXHAUSTED, GRPC_FAILED_PRECONDITION, GRPC_ABORTED, GRPC_OUT_OF_RANGE, GRPC_UNIMPLEMENTED, GRPC_INTERNAL, GRPC_UNAVAILABLE, GRPC_DATA_LOSS, GRPC_UNAUTHENTICATED.

Where the error surfaces depends on how the call is driven: a synchronous unary call raises directly; async and streaming calls raise only submission-time programming errors when created and defer everything time- or server-dependent to fetch/take!/wait/close/detach; put! raises once the call stops accepting requests. references/deadlines-cancellation.md has the full contract.

Legacy API

Still generated by default. One constructor is generated per RPC, named {ServiceName}_{RPCName}_Client, hitting path /{package}.{ServiceName}/{RPCName}. A client is a lightweight value: it holds a handle, host, port, path, and options, so construct one per RPC and reuse it. It takes the same connection options as gRPCChannel, plus constructor-only grpc, TRequest, and TResponse keywords.

julia
client = MyService_MyRPC_Client("localhost", 50051; deadline = 30)
Unary RPC
julia
# Simplest: send and block
response = grpc_sync_request(client, MyRequest(42, UInt64[]))
# Submit now, collect later: lets many requests fly concurrently
reqs = [grpc_async_request(client, MyRequest(i, UInt64[])) for i in 1:10]
for req in reqs
response = grpc_async_await(client, req) # returns the decoded response
end
# Out-of-order completion: handle each response as it lands
ch = Channel{gRPCAsyncChannelResponse{MyResponse}}(10)
for (index, request) in enumerate(requests)
grpc_async_request(client, request, ch, index) # returns nothing
end
for _ in 1:length(requests)
cr = take!(ch) # fields: index, response, ex
isnothing(cr.ex) || throw(cr.ex)
handle(cr.index, cr.response)
end

The channel form never throws at submission time; a failed request arrives as a gRPCAsyncChannelResponse whose ex is set and whose response is nothing, so always check ex before touching response.

Streaming RPC

Requests and responses move through Channels, and the streaming side of the call is chosen by the RPC definition, not by the call site:

RPC variantCall shapegrpc_async_await
Client streaminggrpc_async_request(client, request_c)grpc_async_await(client, req) returns the single response
Server streaminggrpc_async_request(client, request, response_c)grpc_async_await(req) raises only, returns no data
Bidirectionalgrpc_async_request(client, request_c, response_c)grpc_async_await(req) raises only, returns no data

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
63
Repository forks
12
7-day trend score
21

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/juliaio/grpcclient.jl/grpcclient-jl/badge)](https://verified-skill.com/skills/juliaio/grpcclient.jl/grpcclient-jl)

Something wrong with this skill or its page? Tell us.