# `json_rpc`

JSON-RPC 2.0 protocol encoding and decoding library. Provides predicates for constructing, parsing, classifying, and inspecting JSON-RPC 2.0 messages (requests, notifications, responses, and error responses). Also provides stream-based message I/O for implementing JSON-RPC clients and servers, including Content-Length header framing as used by the Language Server Protocol (LSP) and the Model Context Protocol (MCP). Uses the `json` library for JSON parsing and generation.

## API documentation

Open the ../../apis/library_index.html#json_rpc link in a web browser.

## Loading

To load this library, load the `loader.lgt` file:

    | ?- logtalk_load(json_rpc(loader)).

## Testing

To test this library predicates, load the `tester.lgt` file:

    | ?- logtalk_load(json_rpc(tester)).

## Usage

### Constructing JSON-RPC 2.0 messages

Construct requests, notifications, responses, and error responses:

    | ?- json_rpc::request(subtract, [42,23], 1, Request).
    Request = {jsonrpc-'2.0', method-subtract, params-[42,23], id-1}.

    | ?- json_rpc::notification(update, [1,2,3], Notification).
    Notification = {jsonrpc-'2.0', method-update, params-[1,2,3]}.

    | ?- json_rpc::response(19, 1, Response).
    Response = {jsonrpc-'2.0', result-19, id-1}.

    | ?- json_rpc::error_response(-32601, 'Method not found', 1, ErrorResponse).

### Standard error constructors

    | ?- json_rpc::parse_error(Error).
    Error = ...

    | ?- json_rpc::invalid_request(Error).
    Error = ...

    | ?- json_rpc::method_not_found(1, Error).
    Error = ...

    | ?- json_rpc::invalid_params(1, Error).
    Error = ...

    | ?- json_rpc::internal_error(1, Error).
    Error = ...

### Encoding and decoding

    | ?- json_rpc::request(subtract, [42,23], 1, Request),
       json_rpc::encode(Request, JSON).
    JSON = '{"jsonrpc":"2.0","method":"subtract","params":[42,23],"id":1}'.

    | ?- json_rpc::decode('{"jsonrpc":"2.0","result":19,"id":1}', Term).

### Message classification

    | ?- json_rpc::is_request(Message).
    ...

    | ?- json_rpc::is_notification(Message).
    ...

    | ?- json_rpc::is_response(Message).
    ...

    | ?- json_rpc::is_error_response(Message).
    ...

    | ?- json_rpc::is_batch(Messages).
    ...

### Field extraction

    | ?- json_rpc::id(Message, Id).
    ...

    | ?- json_rpc::method(Message, Method).
    ...

    | ?- json_rpc::params(Message, Params).
    ...

    | ?- json_rpc::result(Message, Result).
    ...

    | ?- json_rpc::error_code(Message, Code).
    ...

    | ?- json_rpc::error_message(Message, ErrorMessage).
    ...

    | ?- json_rpc::error_data(Message, Data).
    ...

### Stream I/O (client and server API)

Write and read newline-delimited JSON-RPC messages over streams:

    | ?- json_rpc::write_message(Output, Message).
    ...

    | ?- json_rpc::read_message(Input, Message).
    ...

These predicates can be used with any stream, including socket streams from the `sockets` library, to implement JSON-RPC clients and servers.

### Content-Length framed I/O (LSP/MCP protocols)

Write and read JSON-RPC messages using `Content-Length` header framing as defined by the Language Server Protocol (LSP) and the Model Context Protocol (MCP). Each message is preceded by a `Content-Length: N\r\n\r\n` header where `N` is the byte length of the JSON body:

    | ?- json_rpc::write_framed_message(Output, Message).
    ...

    | ?- json_rpc::read_framed_message(Input, Message).
    ...

`read_framed_message/2` fails at end of stream or if the header is missing or malformed.

## API summary

### Message construction

Predicates for building JSON-RPC 2.0 message terms. Requests include an `id` for matching responses; notifications do not.

- `request(+Method, +Params, +Id, --Request)` - Construct a request

- `request(+Method, +Id, --Request)` - Construct a request with no parameters

- `notification(+Method, +Params, --Notification)` - Construct a notification

- `notification(+Method, --Notification)` - Construct a notification with no parameters

- `response(+Result, +Id, --Response)` - Construct a successful response

- `error_response(+Code, +Message, +Id, --ErrorResponse)` - Construct an error response

- `error_response(+Code, +Message, +Data, +Id, --ErrorResponse)` - Construct an error response with data

### Standard error responses

Convenience predicates for the five standard JSON-RPC 2.0 error codes.

- `parse_error(--ErrorResponse)` - Parse error (-32700)

- `invalid_request(--ErrorResponse)` - Invalid request (-32600)

- `method_not_found(+Id, --ErrorResponse)` - Method not found (-32601)

- `invalid_params(+Id, --ErrorResponse)` - Invalid params (-32602)

- `internal_error(+Id, --ErrorResponse)` - Internal error (-32603)

### Encoding and decoding

Convert between JSON-RPC message terms and JSON atoms (strings).

- `encode(+Term, --JSON)` - Encode a JSON-RPC term to a JSON atom

- `decode(+JSON, --Term)` - Decode a JSON atom to a JSON-RPC term

### Message classification

Test what kind of JSON-RPC message a term represents.

- `is_request(+Term)` - Test if a term is a request

- `is_notification(+Term)` - Test if a term is a notification

- `is_response(+Term)` - Test if a term is a successful response

- `is_error_response(+Term)` - Test if a term is an error response

- `is_batch(+Term)` - Test if a term is a batch (non-empty list)

### Field extraction

Extract individual fields from JSON-RPC message terms.

- `id(+Message, --Id)` - Extract the id field

- `method(+Message, --Method)` - Extract the method field

- `params(+Message, --Params)` - Extract the params field

- `result(+Message, --Result)` - Extract the result field

- `error(+Message, --Error)` - Extract the error object

- `error_code(+Message, --Code)` - Extract the error code

- `error_message(+Message, --ErrorMessage)` - Extract the error message

- `error_data(+Message, --Data)` - Extract the error data

### Stream I/O

Read and write JSON-RPC messages over streams. The newline-delimited variants are suitable for socket-based communication. The Content-Length framed variants implement the header-based framing used by the Language Server Protocol (LSP) and the Model Context Protocol (MCP).

- `write_message(+Output, +Message)` - Write a newline-delimited message

- `read_message(+Input, --Message)` - Read a newline-delimited message

- `write_framed_message(+Output, +Message)` - Write a message with Content-Length framing

- `read_framed_message(+Input, --Message)` - Read a message with Content-Length framing