Lisp-RPC Specification
Table of Contents
1. Introduction
Lisp-RPC is a lightweight, S-expression based Remote Procedure Call protocol. It supports two modes: Plain Mode for direct, dynamic communication and Spec Mode for schema-defined, type-checked communication. Source code.
2. Data Types
Lisp-RPC supports the following data types:
2.1. Primary Types
- string: A standard Lisp string (e.g.,
"hello"). - number: Integers (e.g.,
42). - float: Floating-point numbers (e.g.,
3.14). - boolean: Represented by
T(true) andNIL(false). (Note: In S-expressions,NILalso represents an empty list).
2.2. Complex Types
- Data: A named structure followed by keyword-value pairs.
- Format:
(data-name :key1 value1 :key2 value2 ...) - Example:
(book-info :title "1984" :id 1)
- Format:
- List: A sequence of elements. In Plain Mode, lists must be quoted.
- Format:
'(item1 item2 ...) - Example:
'(1 2 3)
- Format:
- Map (Anonymous Data): A collection of keyword-value pairs without a name. In Plain Mode, maps must be quoted.
- Format:
'(:key1 value1 :key2 value2 ...) - Example:
'(:first "John" :last "Doe")
- Format:
3. Plain Mode
In Plain Mode, the client sends a raw S-expression (as a string) to the server. The server evaluates or parses the call and returns a result in the same format.
3.1. Request Format
A request must be a Data type:
(data-name :param1 value1 :param2 value2)
Example:
(get-book :title "The Hobbit" :year 1937)
3.2. Response Format
The response is also a Data type:
(response-name :result value :status "success")
Example:
(book-info :id "B123" :available T)
3.3. Nested Data
Keywords can take Data, List, or Map types as values.
(update-user :id 1 :profile '(:email "[email protected]" :tags '("admin" "staff")))
4. Spec Mode
Spec Mode allows defining a formal schema for the RPC interface. This enables automatic library generation, type checking, and better error handling.
4.1. Defining a Package
(def-rpc-package package-name)
4.2. Defining Messages (Data Structures)
Use def-msg to define reusable data structures.
(def-msg message-name :key1 'type1 :key2 'type2 ...)
- Types can be primary types (
'string,'number/'int,'float,'boolean). - Types can be other defined messages.
- Types can be nested lists:
(list 'type). - Types can be nested maps:
'(:k1 'type1 :k2 'type2). Anonymous maps MUST be quoted. - Types can be optional:
(optional 'type).
Examples:
(def-msg language-preference :lang 'string)
(def-msg author-list :names (list 'string))
(def-msg user
:id 'number ;; or 'int, if it is float, use 'float
:middle-name (optional 'string)
:meta '(:created-at 'string :active 'boolean)) ;; Quoted map schema
4.3. Defining RPCs
Use def-rpc to define a remote procedure, specifying its input schema and output message type.
(def-rpc rpc-name
'(:param1 'type1 :param2 'type2 ...)
'response-message-name)
Example:
(def-rpc get-book
'(:title 'string :version (optional 'string)
:lang '(:lang 'string :encoding 'number)
:authors 'author-list)
'book-info)
5. Grammar and Validation Rules
- Keywords: All keys in Data and Map types must be Lisp keywords (starting with
:). - Quoting:
- In Plain Mode: Lists and Maps MUST be quoted (e.g.,
'(...)). - In Spec Mode:
- Types in
def-msgare typically quoted symbols (e.g.,'string). - Anonymous maps in
def-msgordef-rpccan be quoted or unquoted (depending on implementation, but consistent quoting is recommended). - Lists in
def-msguse the(list 'type)constructor. - Optional types in
def-msguse the(optional 'type)constructor.
- Types in
- In Plain Mode: Lists and Maps MUST be quoted (e.g.,
- Uniqueness: Keyword names within a single Data or Map structure must be unique.
- Symbols: Use quoted symbols for type references to avoid evaluation errors in dynamic environments.