DEV Community

kuangren chu
kuangren chu

Posted on

Resource-Oriented JSON-RPC (RO-JRPC) 1.0

Resource-Oriented JSON-RPC (RO-JRPC) 1.0

A Backward-Compatible Structured Routing Extension for JSON-RPC 2.0
From: https://github.com/ggzy12345/ro-jrpc/

Field Value
Status Draft
Category Standards Track
Version 1.0 Draft
Depends on JSON-RPC 2.0

Table of Contents

  1. Abstract
  2. Terminology
  3. Compatibility
  4. Request Object
  5. Semantics
  6. Canonical Method Mapping
  7. Example Requests
  8. Responses
  9. Receiver Behavior
  10. Notifications
  11. Discovery
  12. Authorization Model
  13. Transport Independence
  14. Implementation Guidance
  15. Security Considerations
  16. Versioning
  17. Rationale
  18. Caching
  19. Async Results
  20. Example: AI Agent Usage
  21. Example: CLI Usage

1. Abstract

This specification defines Resource-Oriented JSON-RPC (RO-JRPC), a backward-compatible extension to JSON-RPC 2.0 that standardizes structured routing fields for request messages.

RO-JRPC introduces the following extension fields:

  • resource
  • target
  • verb
  • subresource
  • parent

These fields make explicit the semantics commonly encoded inside JSON-RPC method strings such as:

user.create
task.cancel
file.read
Enter fullscreen mode Exit fullscreen mode

RO-JRPC preserves compatibility with existing JSON-RPC 2.0 tooling while enabling improved:

  • Authorization
  • Capability discovery
  • Analytics
  • Code generation
  • Agent/tool protocols
  • CLI/local IPC systems
  • Async result routing

2. Terminology

The key words MUST, SHOULD, MAY, MUST NOT, and SHOULD NOT are to be interpreted as described in RFC 2119.


3. Compatibility

A valid RO-JRPC request MUST also be a valid JSON-RPC 2.0 request.

Therefore:

  • jsonrpc MUST equal "2.0"
  • method MUST be present
  • id follows JSON-RPC 2.0 rules
  • Notifications remain supported

RO-JRPC adds optional members and semantics only.


4. Request Object

4.1 Standard Members

RO-JRPC inherits all JSON-RPC 2.0 request members:

Member Requirement
jsonrpc REQUIRED
method REQUIRED
params OPTIONAL
id OPTIONAL

4.2 Extension Members

All extension members are OPTIONAL. resource and verb MUST appear together — one without the other is invalid. subresource and parent MUST NOT appear unless resource is also present.

Member Type Meaning
resource string Logical entity class or collection
target `string \ number`
verb string Action to perform
subresource string Nested entity class owned by resource
parent `string \ number`
meta object Optional metadata (servers SHOULD NOT trust)
cache `string \ object`
request_id `string \ number`

5. Semantics

5.1 Resource

resource identifies the logical subject of the operation.

Examples: user, task, file, repo, session, tool, agent

5.2 Target

target identifies a specific instance of a resource.

Examples: 42, "abc123", "/tmp/demo.txt", "session-9"

5.3 Verb

verb identifies the requested action.

Recommended verbs:

Verb Meaning
get Retrieve a single resource
list Retrieve multiple resources
create Create a new resource
update Modify an existing resource
delete Remove a resource
execute Run a procedure or tool
cancel Abort an in-progress operation
watch Subscribe to resource changes
describe Return capability metadata
lock Acquire a lock on a resource
unlock Release a lock on a resource

Async result verbs:

Verb Meaning
yield Intermediate async result; more messages expected
return Final async result; no further messages expected

yield and return are used in result messages flowing back to the originating client (see §19). They SHOULD NOT be used in client-to-server requests.

Implementations MAY define custom verbs.

5.4 Sub-Resource

subresource identifies a nested entity class that is owned by and scoped to a resource.

Examples: repoissue, projecttask, sessionmessage, orgmember

Rules:

  • subresource MUST NOT be present unless resource is also present.
  • Nesting beyond one level (sub-sub-resources) is explicitly out of scope. If deeper nesting is required, the resource model SHOULD be flattened.
  • When subresource is present, target identifies a specific instance of the subresource, not of resource.

5.5 Parent

parent identifies the specific instance of resource that owns the subresource being addressed.

  • parent MUST NOT be present unless subresource is also present.
  • parent plays the same role for resource that target plays for subresource.

6. Canonical Method Mapping

When resource and verb are present, method MUST equal:

  • Without subresource: <resource>.<verb>
  • With subresource: <resource>.<subresource>.<verb>
resource subresource verb method
user create user.create
task cancel task.cancel
repo clone repo.clone
repo issue get repo.issue.get
project task list project.task.list
org member delete org.member.delete
job yield job.yield
job return job.return

6.1 Target Exclusion Rule

target SHOULD NOT be embedded in method.

Preferred:

{
  "method": "user.get",
  "resource": "user",
  "target": "42",
  "verb": "get"
}
Enter fullscreen mode Exit fullscreen mode

Avoid:

user.42.get
Enter fullscreen mode Exit fullscreen mode

7. Example Requests

7.1 Create User

{
  "jsonrpc": "2.0",
  "method": "user.create",
  "resource": "user",
  "verb": "create",
  "params": { "name": "Alice" },
  "id": 1
}
Enter fullscreen mode Exit fullscreen mode

7.2 Get User

{
  "jsonrpc": "2.0",
  "method": "user.get",
  "resource": "user",
  "target": "42",
  "verb": "get",
  "id": 2
}
Enter fullscreen mode Exit fullscreen mode

7.3 Cancel Task

{
  "jsonrpc": "2.0",
  "method": "task.cancel",
  "resource": "task",
  "target": "123",
  "verb": "cancel",
  "id": "abc"
}
Enter fullscreen mode Exit fullscreen mode

7.4 Get a Sub-Resource (Issue on a Repo)

{
  "jsonrpc": "2.0",
  "method": "repo.issue.get",
  "resource": "repo",
  "parent": "99",
  "subresource": "issue",
  "target": "7",
  "verb": "get",
  "id": 3
}
Enter fullscreen mode Exit fullscreen mode

7.5 List Sub-Resources (Tasks in a Project)

{
  "jsonrpc": "2.0",
  "method": "project.task.list",
  "resource": "project",
  "parent": "42",
  "subresource": "task",
  "verb": "list",
  "id": 4
}
Enter fullscreen mode Exit fullscreen mode

7.6 Create a Sub-Resource (Message in a Session)

{
  "jsonrpc": "2.0",
  "method": "session.message.create",
  "resource": "session",
  "parent": "session-9",
  "subresource": "message",
  "verb": "create",
  "params": { "content": "Hello" },
  "id": 5
}
Enter fullscreen mode Exit fullscreen mode

8. Responses

Responses MUST remain compliant with JSON-RPC 2.0.

Success:

{
  "jsonrpc": "2.0",
  "result": { "ok": true },
  "id": "abc"
}
Enter fullscreen mode Exit fullscreen mode

Error:

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32600,
    "message": "Invalid Request: verb not supported"
  },
  "id": "abc"
}
Enter fullscreen mode Exit fullscreen mode

9. Receiver Behavior

9.1 Structured Requests

If resource and verb are present, receivers MUST route using those members.

If subresource is also present, receivers MUST route using resource, subresource, and verb together.

9.2 Legacy Requests

If only method is present, receivers MAY route using method parsing or legacy dispatch.

9.3 Mismatch Handling

If method, resource, subresource, and verb are inconsistent — for example:

method   = "user.create"
resource = "task"
verb     = "delete"
Enter fullscreen mode Exit fullscreen mode

Or:

method      = "repo.issue.get"
resource    = "repo"
subresource = "comment"
verb        = "get"
Enter fullscreen mode Exit fullscreen mode

The receiver MUST reject with -32600 Invalid Request.

9.4 Co-presence Rules

The following combinations are invalid and MUST be rejected with -32600:

Condition Invalid because
resource present, verb absent Incomplete structured request
verb present, resource absent Incomplete structured request
subresource present, resource absent Sub-resource requires parent resource
parent present, subresource absent parent is meaningless without sub-resource
target present, resource absent Target has no resource context

10. Notifications

Notifications are requests without id. No response is sent.

{
  "jsonrpc": "2.0",
  "method": "log.create",
  "resource": "log",
  "verb": "create",
  "params": { "message": "started" }
}
Enter fullscreen mode Exit fullscreen mode

11. Discovery

Servers SHOULD support rpc.describe.

Request:

{
  "jsonrpc": "2.0",
  "method": "rpc.describe",
  "resource": "rpc",
  "verb": "describe",
  "id": 1
}
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "jsonrpc": "2.0",
  "result": {
    "protocol": "ro-jrpc",
    "version": "1.0-draft",
    "resources": [
      {
        "name": "user",
        "verbs": ["create", "get", "update", "delete"]
      },
      {
        "name": "task",
        "verbs": ["list", "cancel"]
      },
      {
        "name": "repo",
        "verbs": ["get", "list", "clone"],
        "subresources": [
          { "name": "issue", "verbs": ["get", "list", "create", "delete"] }
        ]
      }
    ]
  },
  "id": 1
}
Enter fullscreen mode Exit fullscreen mode

The protocol and version fields in the result allow clients to confirm RO-JRPC support and negotiate behavior. Servers SHOULD include both.


12. Authorization Model

RO-JRPC enables structured policy systems. The full authorization tuple is:

resource [+ subresource] + verb [+ target | parent]
Enter fullscreen mode Exit fullscreen mode

This is the primary advantage over method-string ACLs — policies can be written at any granularity without string parsing.

Flat resource policies:

allow  user:create
allow  task:get          target=*
deny   file:delete       target=*
allow  file:delete       target=own
Enter fullscreen mode Exit fullscreen mode

Sub-resource policies:

allow  repo:issue:get    parent=*
allow  repo:issue:create parent=own
deny   org:member:delete parent=*
Enter fullscreen mode Exit fullscreen mode

Target wildcards:

  • target=* — any instance
  • target=own — only instances owned by the requesting identity
  • target=<id> — a specific instance

The policy syntax above is illustrative. Implementations MAY define their own policy language; what RO-JRPC standardizes is the tuple structure, not the policy format.


13. Transport Independence

RO-JRPC MAY be used over:

  • stdio
  • pipes
  • Unix domain sockets
  • TCP
  • HTTP
  • WebSocket
  • Child-process IPC

14. Implementation Guidance

Preferred Internal Router API

// Flat resources
router.resource("user").verb("create", handler)
router.resource("task").verb("cancel", handler)

// Sub-resources
router.resource("repo").subresource("issue").verb("get", handler)
router.resource("project").subresource("task").verb("list", handler)

// Async result verbs
router.resource("job").verb("yield", handler)
router.resource("job").verb("return", handler)
Enter fullscreen mode Exit fullscreen mode

Compatibility Adapter

If structured members are absent, receivers MAY parse method:

user.create        →  resource=user  verb=create
repo.issue.get     →  resource=repo  subresource=issue  verb=get
Enter fullscreen mode Exit fullscreen mode

Single-segment methods (e.g. ping, health) MAY be treated as plain JSON-RPC 2.0 and routed via legacy dispatch. Three-or-more-segment methods that do not match <resource>.<subresource>.<verb> SHOULD be rejected with -32600.


15. Security Considerations

Servers MUST validate:

  • Allowed resources
  • Allowed verbs
  • Target ownership
  • Params schema

Servers SHOULD NOT trust client-supplied meta.

Receivers SHOULD validate that request_id in async result messages references a known outstanding request before dispatching.


16. Versioning

RO-JRPC does not alter jsonrpc. Requests MUST continue using:

"jsonrpc": "2.0"
Enter fullscreen mode Exit fullscreen mode

Protocol capability MAY be advertised through rpc.describe or transport negotiation.


17. Rationale

JSON-RPC method strings commonly encode structure informally:

user.create
task.cancel
tool.execute
Enter fullscreen mode Exit fullscreen mode

RO-JRPC standardizes this widespread convention into explicit, machine-readable fields — enabling routing, authorization, and tooling that do not require method string parsing.


18. Caching

Both client and server MAY maintain their own cache independently. No negotiation is required for the basic case.

The natural cache key is: resource + verb + target (plus subresource + parent when present). Verbs get and list are cacheable by nature; create, update, and delete are not. Implementations SHOULD invalidate cached entries for a resource when a mutating verb (create, update, delete) is observed for that resource.

18.1 Cache Directive on Responses

Servers MAY include a cache field on responses to hint TTL to clients:

{
  "jsonrpc": "2.0",
  "result": { "id": "42", "name": "Alice" },
  "cache": { "max-age": 60 },
  "id": 1
}
Enter fullscreen mode Exit fullscreen mode
Field Type Meaning
max-age integer Seconds the result may be reused by the client

18.2 Cache Directive on Requests

Clients MAY include a cache field on requests to bypass the server cache:

{
  "jsonrpc": "2.0",
  "method": "user.get",
  "resource": "user",
  "verb": "get",
  "target": "42",
  "cache": "no-cache",
  "id": 1
}
Enter fullscreen mode Exit fullscreen mode
Value Meaning
no-cache Server SHOULD NOT serve a cached result

Implementations MAY extend the cache object with additional directives. Unrecognised directives MUST be ignored.


19. Async Results

RO-JRPC supports async result delivery through resource-oriented result messages. Whether delivery is push or pull, and whether the originating request is sync or async, is left to the implementation and transport.

19.1 Async Result Verbs

Two reserved verbs are defined for result messages flowing from server to client:

Verb Meaning
yield Intermediate result; more messages expected
return Final result; no further messages will be sent

These verbs SHOULD NOT be used in client-to-server requests.

19.2 Result Message Structure

An async result message is itself a resource-oriented RO-JRPC message. The resource in the result does not need to match the resource of the originating request — for example, a long-running operation initiated on any resource may deliver results as a job resource.

The id field in the result message SHOULD match the id of the originating request when the result is delivered on the same connection or channel. When delivered on a different channel, or when there is no single originating request (pure event-driven), request_id MAY be used instead.

19.3 request_id

request_id is an optional field that explicitly correlates an async result back to the originating request. It SHOULD be included when:

  • The result is delivered on a different channel or connection from the original request
  • The result resource differs from the request resource (e.g. job.yield in response to attachment.create)

request_id MAY be omitted for pure event-driven cases where no single originating request exists, such as session events scoped by target.

19.4 Examples

Intermediate result (upload attachment → job):

{
  "jsonrpc": "2.0",
  "method": "job.yield",
  "resource": "job",
  "verb": "yield",
  "target": "job-123",
  "result": { "status": "pending", "progress": 60, "stage": "scanning" },
  "request_id": "req-001"
}
Enter fullscreen mode Exit fullscreen mode

Final result (upload attachment → job):

{
  "jsonrpc": "2.0",
  "method": "job.return",
  "resource": "job",
  "verb": "return",
  "target": "job-123",
  "result": { "status": "done", "attachmentId": "att-456" },
  "request_id": "req-001"
}
Enter fullscreen mode Exit fullscreen mode

Session event (pure event-driven, no request_id):

{
  "jsonrpc": "2.0",
  "method": "session.yield",
  "resource": "session",
  "verb": "yield",
  "target": "session-9",
  "result": { "status": "pending", "content": "Thinking..." }
}
Enter fullscreen mode Exit fullscreen mode

Session final result:

{
  "jsonrpc": "2.0",
  "method": "session.return",
  "resource": "session",
  "verb": "return",
  "target": "session-9",
  "result": { "status": "done", "content": "Here is your answer." }
}
Enter fullscreen mode Exit fullscreen mode

19.5 Status Field

The result object SHOULD include a status field when using async result verbs:

Status Meaning
accepted Request received and queued, not yet started
pending In progress, more results expected
done Completed successfully
error Failed; no further messages will be sent

status is a convention within result — it is not a top-level envelope field.


20. Example: AI Agent Usage

{
  "jsonrpc": "2.0",
  "method": "tool.execute",
  "resource": "tool",
  "target": "web-search",
  "verb": "execute",
  "params": { "query": "rust async" },
  "id": "req1"
}
Enter fullscreen mode Exit fullscreen mode

21. Example: CLI Usage

{
  "jsonrpc": "2.0",
  "method": "build.execute",
  "resource": "build",
  "verb": "execute",
  "params": { "target": "linux" },
  "id": "1"
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)