protoc-gen-nexus

module
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 24, 2024 License: MIT

README

protoc-gen-nexus

A Protobuf plugin for generating Nexus code.

⚠️ EXPERIMENTAL: Generated code structure is subject to change as feedback is collected. ⚠️

Supported languages:

  • Golang
  • Java (TBD)

Installation

  1. Download an archive from the latest release.
  2. Extract and add to your system's path.
Using go install
go install github.com/bergundy/protoc-gen-nexus/cmd/protoc-gen-nexus@latest

Usage

Create a proto file

NOTE: the directory structure here determines the directory structure of the generated files.

example/v1/service.proto

syntax="proto3";

package example.v1;

option go_package = "github.com/bergundy/greet-nexus-example/gen/example/v1;example";

message GreetInput {
  string name = 1;
}

message GreetOutput {
  string greeting = 1;
}

service Greeting {
  rpc Greet(GreetInput) returns (GreetOutput) {
  }
}
Create buf config files

NOTE: Alternatively you may use protoc directly.

buf.yaml

version: v2
modules:
  - path: .
deps:
  - buf.build/bergundy/protoc-gen-nexus
lint:
  use:
    - BASIC
  except:
    - FIELD_NOT_REQUIRED
    - PACKAGE_NO_IMPORT_CYCLE
breaking:
  use:
    - FILE
  except:
    - EXTENSION_NO_DELETE
    - FIELD_SAME_DEFAULT

buf.gen.yaml

version: v2
clean: true
managed:
  enabled: true
plugins:
  - remote: buf.build/protocolbuffers/go
    out: gen
    opt:
      - paths=source_relative
  - local: protoc-gen-nexus
    out: gen
    strategy: all
    opt:
      - paths=source_relative
      - lang=go
Generate code
buf generate
Create a handler and serve on localhost:7243

server/main.go

package main

import (
        "context"
        "log"
        "net"
        "net/http"

        "github.com/bergundy/greet-nexus-example/gen/example/v1"
        "github.com/bergundy/greet-nexus-example/gen/example/v1/examplenexus"
        "github.com/nexus-rpc/sdk-go/contrib/nexusproto"
        "github.com/nexus-rpc/sdk-go/nexus"
)

type handler struct {
        examplenexus.UnimplementedGreetingNexusServiceHandler
}

func (h *handler) Greet(name string) nexus.Operation[*example.GreetInput, *example.GreetOutput] {
        return nexus.NewSyncOperation(name, func(ctx context.Context, input *example.GreetInput, options nexus.StartOperationOptions) (*example.GreetOutput, error) {
                return &example.GreetOutput{
                        Greeting: "Hello, " + input.Name,
                }, nil
        })
}

func main() {
        service, err := examplenexus.NewGreetingNexusService(&handler{})
        if err != nil {
                log.Fatal(err)
        }
	        if err != nil {
                log.Fatal(err)
        }
        registry := nexus.NewServiceRegistry()
        if err := registry.Register(service); err != nil {
                log.Fatal(err)
        }
        rh, err := registry.NewHandler()
        if err != nil {
                log.Fatal(err)
        }
        h := nexus.NewHTTPHandler(nexus.HandlerOptions{
                Handler:    rh,
                Serializer: nexusproto.Serializer(nexusproto.SerializerModePreferJSON),
        })

        listener, err := net.Listen("tcp", "localhost:7243")
        if err != nil {
                log.Fatal(err)
        }
        defer listener.Close()
        if err = http.Serve(listener, h); err != nil {
                log.Fatal(err)
        }
}

go run ./server

Execute an operation with the generated client

client/main.go

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/bergundy/greet-nexus-example/gen/example/v1"
	"github.com/bergundy/greet-nexus-example/gen/example/v1/examplenexus"
	"github.com/nexus-rpc/sdk-go/nexus"
)

func main() {
	ctx := context.Background()
	c, err := examplenexus.NewGreetingNexusHTTPClient(nexus.HTTPClientOptions{
		BaseURL: "http://localhost:7243",
	})
	if err != nil {
		log.Fatal(err)
	}
	output, err := c.Greet(ctx, &example.GreetInput{Name: "World"}, nexus.ExecuteOperationOptions{})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("got sync greeting:", output.Greeting)
	result, err := c.GreetAsync(ctx, &example.GreetInput{Name: "World"}, nexus.StartOperationOptions{})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("got async greeting:", result.Successful.Greeting)
}

go run ./client

Options

Service
(nexus.v1.service).name

string

Defines the Nexus Service name. Defaults to the proto Service full name.

Example:

syntax = "proto3";

package example.v1;

import "nexus/v1/options.proto";

service ExampleService {
  option (nexus.v1.service).name = "example.v1.Example";
}
Method
(nexus.v1.operation).name

string

Defines the Nexus Operation name. Defaults to the proto Method name.

Example:

syntax = "proto3";

package example.v1;

import "nexus/v1/options.proto";

service ExampleService {
  rpc Foo(FooInput) returns (FooResponse) {
	option (nexus.v1.operation).name = "foo";
  }
}

Contributing

Prerequisites
  • Go >=1.23
  • Buf
Generate the proto extension's Go code
rm -rf ./gen && buf generate
Build the plugin
go build ./cmd/...
Generate example code from protos
(cd example && PATH=${PWD}/..:${PATH} buf generate)
Run sanity tests
go test ./...
Lint code

Install the latest version of golangci-lint and run:

golangci-lint run ./...

Directories

Path Synopsis
cmd
gen
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL