Skip to content
eldoyPublic

About

JSON JARPC Protocol Specification

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

jarpc

JSON Application RPC, version 1.0 draft.

JARPC, pronounced jarpsee, stands for JSON Application RPC.

JARPC is a standard JSON RPC protocol optimized for web applications. It uses HTTP paths as procedure names, JSON request bodies for parameters, and a consistent response envelope for application results.

Design Goals

  • Keep request and response bodies flat and predictable.
  • Map naturally to HTTP routes and backend files.
  • Work well with JavaScript fetch().
  • Work well with plain HTML forms and FormData.
  • Avoid nested form conventions, dot-path parsing, and heavy serializers.
  • Standardize common application concerns such as validation errors and pagination.
  • Remain mechanically adaptable to JSON-RPC and MCP.

Endpoint Model

The HTTP path identifies the procedure.

POST /users/create
Content-Type: application/json

Request:

{
  "id": "r-1001",
  "params": {
    "email": "ada@example.com",
    "password": "secret"
  }
}

There is no body-level method. The route path is the method. The request method is usually POST, not GET.

Request Format

type JARPCRequest<P = unknown> = {
  id?: string | number
  params?: P
}

Fields:

  • id: optional request correlation identifier.
  • params: endpoint input parameters.

If id is present, the response must echo it exactly. If id is omitted, the response should omit it.

For form-oriented endpoints, params should usually be a flat object whose keys match HTML input name attributes.

var params = Object.fromEntries(new FormData(form))

JARPC does not define dot-notation or bracket-notation expansion for nested form values. Field names are opaque strings.

Success Response

A successful response has ok: true.

{
  "ok": true,
  "id": "r-1001",
  "data": {
    "userId": 42
  }
}

Success with no returned data:

{
  "ok": true,
  "id": "r-1001"
}

Fields:

  • ok: required, always true for success.
  • id: echoed only when supplied by the request.
  • data: primary successful return value.
  • pagination: standardized pagination metadata, when applicable.
  • details: endpoint-specific supplemental information, when documented.

Error Response

An error response has ok: false.

{
  "ok": false,
  "id": "r-1001",
  "message": "Unauthorized",
  "code": "UNAUTHORIZED"
}

Fields:

  • ok: required, always false for application failure.
  • id: echoed only when supplied by the request.
  • message: human-readable error message.
  • code: optional stable machine-readable error code. It may be a string or number.
  • fields: standardized field/input validation errors.
  • details: endpoint-specific supplemental information, when documented.

Validation Errors

Field validation errors must use fields.

{
  "ok": false,
  "id": "r-1001",
  "message": "Validation failed",
  "code": "VALIDATION_ERROR",
  "fields": {
    "email": ["Must be a valid email"],
    "password": ["Must be at least 12 characters"]
  }
}

fields is a flat object whose keys are field names and whose values are arrays of validation messages.

Field names are opaque strings and should normally match HTML input name attributes.

<input name="email" />
<input name="company_name" />
<input name="items_0_name" />

Example:

{
  "fields": {
    "company_name": ["Required"],
    "items_0_name": ["Required"]
  }
}

JARPC does not define nested field syntax. It does not require clients to parse dot notation, bracket notation, or object paths.

Field errors must not be placed in details.

Flat Form Principle

JARPC favors flat form flows.

For web application forms, deeply nested form payloads often require custom serializers, path parsers, deep merging, and fragile error mapping. JARPC avoids prescribing those mechanisms.

A simple form can be serialized with:

var params = Object.fromEntries(new FormData(form))

And field errors can be mapped back with:

for (var [name, messages] of Object.entries(result.fields || {})) {
  var input = form.elements.namedItem(name)
  showFieldError(input, messages)
}

Applications should prefer flat field names and, when useful, multi-step flows over deeply nested form payloads.

Pagination

Paginated responses must use pagination.

Page-based pagination:

{
  "ok": true,
  "data": [
    {
      "id": 1,
      "name": "Ada"
    }
  ],
  "pagination": {
    "page": 1,
    "pageSize": 20,
    "total": 134,
    "hasMore": true
  }
}

Cursor-based pagination:

{
  "ok": true,
  "data": [
    {
      "id": 1,
      "name": "Ada"
    }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6MX0=",
    "previousCursor": null,
    "hasMore": true
  }
}

Pagination metadata must not be placed in details.

Suggested type:

type Pagination =
  | {
      page: number
      pageSize: number
      total?: number
      hasMore?: boolean
    }
  | {
      nextCursor?: string | null
      previousCursor?: string | null
      hasMore: boolean
    }

Details

details is an endpoint-specific supplemental field.

{
  "ok": false,
  "message": "Import failed",
  "code": "IMPORT_FAILED",
  "details": {
    "row": 17,
    "column": "email",
    "rawValue": "not-an-email"
  }
}

Rules:

  • details has no global meaning.
  • Each endpoint that returns details must document its structure and meaning.
  • Do not use details for standardized concepts such as fields or pagination.

HTTP Status Codes

JARPC separates transport status from application status.

Application results are represented by the JSON envelope:

{
  "ok": false,
  "message": "User not found",
  "code": "USER_NOT_FOUND"
}

This may be returned with HTTP 200, because the endpoint executed successfully and returned an application-level result.

Recommended HTTP status usage:

  • 200: endpoint executed and returned a JARPC result, whether ok is true or false.
  • 404: endpoint/path does not exist.
  • 500: server crash or unexpected infrastructure failure.
  • 429: request throttled before normal endpoint execution.
  • 301 / 302: HTTP-level redirect.
  • 401 / 403: HTTP-level auth only, such as Basic Auth, proxy auth, or middleware rejection.

Application authentication and authorization errors should normally use HTTP 200 with ok: false:

{
  "ok": false,
  "message": "Please sign in",
  "code": "UNAUTHENTICATED"
}
{
  "ok": false,
  "message": "You do not have permission to do that",
  "code": "UNAUTHORIZED"
}

Usage

var response = await fetch('/users/create', {
  method: 'POST',
  headers: {
    'content-type': 'application/json'
  },
  body: JSON.stringify({
    id: 'r-1001',
    params: Object.fromEntries(new FormData(form))
  })
})

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`)
}

var result = await response.json()

if (!result.ok) {
  displayErrors(result)
  return
}

render(result.data)

There are two levels of success:

response.ok // HTTP/transport success
result.ok // application success

Type Definition

type JARPCId = string | number

type FieldErrors = Record<string, string[]>

type Pagination =
  | {
      page: number
      pageSize: number
      total?: number
      hasMore?: boolean
    }
  | {
      nextCursor?: string | null
      previousCursor?: string | null
      hasMore: boolean
    }

type JARPCRequest<P = unknown> = {
  id?: JARPCId
  params?: P
}

type JARPCSuccess<T = unknown, D = unknown> = {
  ok: true
  id?: JARPCId
  data?: T
  pagination?: Pagination
  details?: D
}

type JARPCFailure<D = unknown> = {
  ok: false
  id?: JARPCId
  message: string
  code?: string | number
  fields?: FieldErrors
  details?: D
}

type JARPCResponse<T = unknown, D = unknown> =
  JARPCSuccess<T, D> | JARPCFailure<D>

JSON-RPC / MCP Adaptation

JARPC can be adapted to JSON-RPC by treating the HTTP path as the JSON-RPC method.

JARPC request:

POST /users/create
{
  "id": "r-1001",
  "params": {
    "email": "ada@example.com"
  }
}

JSON-RPC request:

{
  "jsonrpc": "2.0",
  "id": "r-1001",
  "method": "users/create",
  "params": {
    "email": "ada@example.com"
  }
}

JARPC success:

{
  "ok": true,
  "id": "r-1001",
  "data": {
    "userId": 42
  }
}

JSON-RPC success:

{
  "jsonrpc": "2.0",
  "id": "r-1001",
  "result": {
    "data": {
      "userId": 42
    }
  }
}

JARPC validation error:

{
  "ok": false,
  "id": "r-1001",
  "message": "Validation failed",
  "code": "VALIDATION_ERROR",
  "fields": {
    "email": ["Must be a valid email"]
  }
}

JSON-RPC error:

{
  "jsonrpc": "2.0",
  "id": "r-1001",
  "error": {
    "code": -32602,
    "message": "Validation failed",
    "data": {
      "appCode": "VALIDATION_ERROR",
      "fields": {
        "email": ["Must be a valid email"]
      }
    }
  }
}

JARPC is therefore suitable as a native web application protocol, while still being mechanically adaptable to JSON-RPC-based systems such as MCP.

Created by Vidar Eldøy

About

JSON JARPC Protocol Specification

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors