protoc-gen-connect-openapi

repository·main·Indexed 43 days ago

https://github.com/sudorandom/protoc-gen-connect-openapi

A protobuf plugin that generates OpenAPI v3.1 specifications and JSON Schema (draft 2020-12) documents from protobuf definitions matching the Connect protocol. It supports Connect RPC, google.api.http, Twirp, Gnostic, and Protovalidate annotations, allowing developers to document Connect-based services as standard HTTP/JSON APIs.

Tokens
8K
Snippets
15
Records
21
Agent score
55%

What's inside protoc-gen-connect-openapi

  1. How Protovalidate annotations translate to OpenAPI

    main

    The protoc-gen-connect-openapi plugin supports many Protovalidate annotations, translating them into standard OpenAPI schema constraints where possible.

    Standard Constraints

    Simple numeric or length constraints are mapped to direct OpenAPI properties. For example, a Protobuf gte (greater than or equal to) constraint on an int32 field is translated to the OpenAPI minimum property.

    Custom CEL Expressions

    For complex validation logic using Common Expression Language (CEL), the plugin appends the CEL expression and its associated message to the OpenAPI description field of the property. This ensures that the custom validation logic is documented in the resulting OpenAPI specification even if it cannot be represented as a standard JSON Schema constraint.

    syntax = "proto3";
    
    import "buf/validate/validate.proto";
    
    message User {
      int32 age = 1 [(buf.validate.field).int32.gte = 18];
    }

    // Results in:

    components:
      schemas:
        User:
          properties:
            age:
              minimum: 18
              type: integer
  2. Understand remote plugin restrictions in protoc-gen-connect-openapi

    main

    When using protoc-gen-connect-openapi as a remote plugin (e.g., with buf), the plugin is subject to security restrictions that prevent it from accessing the local filesystem or the network.

    Because of these restrictions, the following options are disabled and will cause an error if used in a remote context:

    • base: The path to a base OpenAPI file used to populate fields not handled by this tool.
    • override: The path to an override OpenAPI file used to override schema components.
  3. Install protoc-gen-connect-openapi using Go 1.24+ 'go tool' support

    main

    For users on Go 1.24 or later, you can use the new go tool support. This allows you to manage the plugin as a tool dependency.

    To use this with buf, configure your buf.gen.yaml to call the tool via go tool.

    go get -tool github.com/sudorandom/protoc-gen-connect-openapi@latest
    go tool protoc-gen-connect-openapi --version
    version: v2
    plugins:
      - local: ["go", "tool", "protoc-gen-connect-openapi"]
        out: gen
  4. Install protoc-gen-connect-openapi using Go

    main

    You can install the binary directly using go install. Note that this is not the recommended method, but it is available.

    Alternatively, if you are using buf, you can use go run directly within your buf.gen.yaml configuration to avoid a manual installation step.

    go install github.com/sudorandom/protoc-gen-connect-openapi@latest
    protoc-gen-connect-openapi --version
    version: v2
    plugins:
      - local: ["go", "run", "github.com/sudorandom/protoc-gen-connect-openapi@latest"]
        out: gen
  5. Generate OpenAPI specs using buf

    main

    You can use the plugin in two ways with buf:

    1. Remote Plugin (BSR): Use the plugin hosted on the Buf Schema Registry. This requires no local installation.
    2. Local Plugin: Use the plugin installed on your local machine.

    When using the remote plugin, you can provide a base OpenAPI file via the opt field.

    # Remote Plugin Example
    version: v2
    plugins:
      - remote: buf.build/community/sudorandom-connect-openapi:v0.19.1
        out: gen
        opt:
        - base=example.base.yaml
    
    # Local Plugin Example
    version: v2
    plugins:
      - local: protoc-gen-connect-openapi
        out: gen
        opt:
        - base=example.base.yaml
  6. Use Gnostic annotations as an alternative to base/override files

    main

    If you are using protoc-gen-connect-openapi as a remote plugin, you cannot use base or override file paths. Instead, use Gnostic annotations to embed OpenAPI specification details directly within your .proto files. This method is fully compatible with remote plugins because it does not require filesystem access.

    This is a common way to define top-level document information (like title, version, and description) that would otherwise be placed in a base file.

    syntax = "proto3";
    
    package my.service.v1;
    
    import "gnostic/openapi/v3/annotations.proto";
    
    option (gnostic.openapi.v3.document) = {
      info: {
        title: "My Awesome API";
        version: "1.0.0";
        description: "This is a sample server for a pet store.";
        contact: {
          name: "API Support";
          url: "http://www.example.com/support";
          email: "support@example.com";
        }
        license: {
          name: "Apache 2.0";
          url: "http://www.apache.org/licenses/LICENSE-2.0.html";
        }
      }
    };
    
    service MyService {
      // ...
    }
  7. Use a local plugin to enable base and override options

    main
    If your workflow requires the use of the base or override options (which require filesystem access), you must run protoc-gen-connect-openapi as a local plugin rather than a remote plugin. Refer to the main README.md for instructions on setting up a local plugin execution environment.
  8. Run tooling demos with `just demo`

    main

    The demo directory allows you to verify the plugin's output (OpenAPI specs and JSON Schema bundles) against various downstream documentation and type-generation tools.

    From the repository root, you can pass a .proto file or an already generated spec file to the just demo command. This command builds the plugin from the working tree, generates the necessary artifacts, runs them through the demo toolchain, and serves a web interface to view the results.

    Key behaviors:

    • First run: Installs the toolchain and npm dependencies.
    • Output: Builds artifacts into demo/out/<name>/. An index page is generated for each demo, and a root index links all built demos.
    • Serving: Results are served at http://localhost:4173 (you can pass a second argument to specify a different port).
    • Error handling: If a tool fails on a specific input (e.g., due to imperfect JSON Schema 2020-12 support), it is reported and skipped rather than aborting the entire build.
    # Run demo for a specific proto file
    just demo internal/converter/testdata/standard/helloworld.proto
    
    # Run demo for a specific JSON schema proto file
    just demo internal/converter/testdata/jsonschema/jsonschema.proto
    
    # Run demo for an existing spec file
    just demo path/to/your.openapi.yaml
    
    # Run demo on a custom port
    just demo internal/converter/testdata/standard/helloworld.proto 8080
  9. Install protoc-gen-connect-openapi via asdf

    main

    If you use asdf for version management, you can install the plugin using the following commands:

    $ asdf plugin add protoc-gen-connect-openapi https://github.com/sudorandom/asdf-protoc-gen-connect-openapi.git
    $ asdf list all protoc-gen-connect-openapi
    $ asdf install protoc-gen-connect-openapi latest
    $ asdf global protoc-gen-connect-openapi latest
  10. Generate OpenAPI specs with protoc

    main

    The tool works as a standard protoc plugin. You can control the output format and configuration using --connect-openapi_opt.

    Common configurations include:

    • Specifying a JSON output format.
    • Providing a base OpenAPI file.
    • Limiting content types (e.g., only json).
    # Basic usage
    protoc internal/converter/fixtures/helloworld.proto --connect-openapi_out=gen
    
    # With JSON format
    protoc internal/converter/fixtures/helloworld.proto \
        --connect-openapi_out=gen \
    --connect-openapi_opt=format=json
    
    # With a base file and specific content types
    protoc internal/converter/fixtures/helloworld.proto \
        --connect-openapi_out=gen \
        --connect-openapi_opt=base=example.base.yaml,content-types=json
  11. How to add a new tool to the demo suite

    main

    To extend the demo suite with a new downstream tool, follow these steps:

    1. Extend the build script: Modify scripts/build_demo.sh by adding a new run_step and add_artifact pair.
    2. Add dependencies: If the tool is an npm-based utility, add it to the package.json file within the demo/ directory.
  12. Configure generator features

    main

    The features option controls which protocol-specific annotations and functionalities are enabled. You must enable at least one of connectrpc, google.api.http, or twirp.

    Available features:

    • connectrpc: Support for Connect RPC.
    • google.api.http: Support for google.api.http annotations (gRPC-Gateway style).
    • twirp: Support for Twirp RPC.
    • gnostic: Support for Gnostic OpenAPI v3 annotations.
    • protovalidate: Support for Protovalidate annotations.

    Note: If you use the features option, it overrides the default set (connectrpc;google.api.http;gnostic;protovalidate).

    # Enable only ConnectRPC support
    opt:
      - features=connectrpc
    
    # Enable Google API HTTP and Protovalidate support
    opt:
      - features=google.api.http;protovalidate
    
    # Enable all features
    opt:
      - features=connectrpc;google.api.http;twirp;gnostic;protovalidate