**JARPC 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. It aims to be wider and more practical than existing standards, improving developer experience and code readability. **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. ```http POST /users/create Content-Type: application/json ``` Request: ```json { "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** ```ts type JARPCRequest

= { 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. ```js 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`. ```json { "ok": true, "id": "r-1001", "data": { "userId": 42 } } ``` Success with no returned data: ```json { "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`. ```json { "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`. ```json { "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. ```html ``` Example: ```json { "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: ```js var params = Object.fromEntries(new FormData(form)); ``` And field errors can be mapped back with: ```js 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: ```json { "ok": true, "data": [ { "id": 1, "name": "Ada" } ], "pagination": { "page": 1, "pageSize": 20, "total": 134, "hasMore": true } } ``` Cursor-based pagination: ```json { "ok": true, "data": [ { "id": 1, "name": "Ada" } ], "pagination": { "nextCursor": "eyJpZCI6MX0=", "previousCursor": null, "hasMore": true } } ``` Pagination metadata must not be placed in `details`. Suggested type: ```ts 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. ```json { "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: ```json { "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`: ```json { "ok": false, "message": "Please sign in", "code": "UNAUTHENTICATED" } ``` ```json { "ok": false, "message": "You do not have permission to do that", "code": "UNAUTHORIZED" } ``` **Client Usage** ```js 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: ```js response.ok // HTTP/transport success result.ok // application success ``` **Type Definition** ```ts type JARPCId = string | number; type FieldErrors = Record; type Pagination = | { page: number; pageSize: number; total?: number; hasMore?: boolean; } | { nextCursor?: string | null; previousCursor?: string | null; hasMore: boolean; }; type JARPCRequest

= { id?: JARPCId; params?: P; }; type JARPCSuccess = { ok: true; id?: JARPCId; data?: T; pagination?: Pagination; details?: D; }; type JARPCFailure = { ok: false; id?: JARPCId; message: string; code?: string | number; fields?: FieldErrors; details?: D; }; type JARPCResponse = | JARPCSuccess | JARPCFailure; ``` **JSON-RPC / MCP Adaptation** JARPC can be adapted to JSON-RPC by treating the HTTP path as the JSON-RPC method. JARPC request: ```http POST /users/create ``` ```json { "id": "r-1001", "params": { "email": "ada@example.com" } } ``` JSON-RPC request: ```json { "jsonrpc": "2.0", "id": "r-1001", "method": "users/create", "params": { "email": "ada@example.com" } } ``` JARPC success: ```json { "ok": true, "id": "r-1001", "data": { "userId": 42 } } ``` JSON-RPC success: ```json { "jsonrpc": "2.0", "id": "r-1001", "result": { "data": { "userId": 42 } } } ``` JARPC validation error: ```json { "ok": false, "id": "r-1001", "message": "Validation failed", "code": "VALIDATION_ERROR", "fields": { "email": ["Must be a valid email"] } } ``` JSON-RPC error: ```json { "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.