Skip to content

Conversation

Velnbur
Copy link

@Velnbur Velnbur commented Oct 5, 2025

Description

This PR implements optional generation of rpc.discover method which returns OpenRPC specification from trait definition. For that open-rpc crate was forked to fix compatibility issues with official examples and to add some useful conversion functions (about that a little bit later).

This works by using utoipa::schema! and utoipa::ToSchema crate macros, that generate utoipa::openapi::Schema structure at runtime, which later converted to open_rpc::Schema and, with information from server trait definition, to open_rpc::ContentDescriptor.

With these information about each trait method, open_rpc::OpenRpc structure is constructed inside rpc.discover method at runtime. For now it's constructed on each rpc.discover call, but this can be improved by adding some lazy static variable.

Functionality

For example, you can take a look at examples/examples/rpc_discover.rs, run it:

cd examples && cargo run --example rpc_discover

then send request to server:

curl -X POST -H "Content-Type: application/json" http://127.0.0.1:8080 -d '{"jsonrpc": "2.0","id":"id", "method": "rpc.discover"}' | jq .result
Response
{
  "openrpc": "1.0.0-rc1",
  "info": {
    "title": "Rpc",
    "version": ""
  },
  "servers": [],
  "methods": [
    {
      "name": "foo",
      "description": "",
      "params": [
        {
          "name": "param_a",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        },
        {
          "name": "param_b",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "result": {
        "name": "return",
        "required": true,
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      }
    },
    {
      "name": "add",
      "description": "",
      "params": [
        {
          "name": "request",
          "required": true,
          "schema": {
            "type": "object",
            "properties": {
              "a": {
                "type": "integer",
                "minimum": 0
              },
              "b": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "a",
              "b"
            ]
          }
        }
      ],
      "result": {
        "name": "return",
        "required": true,
        "schema": {
          "type": "object",
          "properties": {
            "sum": {
              "type": "integer",
              "minimum": 0
            }
          },
          "required": [
            "sum"
          ]
        }
      }
    },
    {
      "name": "calculate",
      "description": "",
      "params": [
        {
          "name": "args",
          "required": true,
          "schema": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          }
        },
        {
          "name": "operation",
          "required": true,
          "schema": {
            "type": "string",
            "enum": [
              "add",
              "mul",
              "sub"
            ]
          }
        }
      ],
      "result": {
        "name": "return",
        "required": true,
        "schema": {
          "type": "integer"
        }
      }
    }
  ]
}

copy response, and introspect it, for example, using OpenRPC Playground.

@Velnbur
Copy link
Author

Velnbur commented Oct 5, 2025

Not sure what to do with open-rpc crate, as original author seems to abandon it, maybe it can be as part of the OpenRPC organization or jsonrpsee crates

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant