@tobi2409/proc2rest
v0.8.2
Published
Generate REST endpoints and JS clients from TypeScript RPC functions
Maintainers
Readme
proc2rest
A code generator that converts TypeScript RPC functions into REST APIs with automatic client generation.
Experimental status: This project is still in its testing phase. It has not yet been sufficiently hardened or validated for production use and is therefore not recommended for production deployments.
Overview
proc2rest generates:
- Express.js server routes from TypeScript functions
- JavaScript ES modules API clients with full type support
- Support for JSON and binary (MessagePack) transport formats
Key Features
- Automatic REST Endpoint Generation: Exported functions marked with
@restbecome REST endpoints - Binary Data Support: Type-aware detection of binary parameters (Uint8Array, ArrayBuffer, Blob, etc.)
- MessagePack Transport: Efficient binary serialization for endpoints with binary parameters
- ES Module Clients: Auto-generated JS clients as native ES modules
- CORS & Configuration: Centralized config via
proc2rest.config.json - Handlebars-based Templates: Stable code generation via adapter-owned templates
Configuration
Create proc2rest.config.json in your project root:
{
"jsClients": ["src/client/index.js"],
"servers": [
{ "src": "src/server/first/my-server.ts", "namespace": "myServer" }
],
"rawServerFiles": ["src/server/my-server-raw.ts"],
"apiUrl": "http://localhost:3000",
"cors": { "allowOrigin": "*" },
"rateLimit": {
"windowDurationMs": 900000,
"maxRequests": 100,
"useStandardHeaders": true,
"useLegacyHeaders": false
},
"errorStatusCodes": {
"UnsupportedArgumentError": 422
},
"method-rules": {
"GET": "^(get|list|find)",
"POST": "^(create|add|insert)",
"PATCH": "^(update|set|patch)",
"DELETE": "^(delete|remove)"
},
"method-rules-custom-functions": {
"getBinDataInfo": "POST"
},
"binaryTypes": ["ArrayBuffer", "Uint8Array", "Buffer", "Blob", "File"]
}Config Fields:
jsClients: JS client source files that should receive@server-importinjectionservers: Array of server descriptors with:src: server source pathnamespace: import namespace used for generated routes and clients
rawServerFiles: extra server files to inline intoroutes.generated.tsapiUrl: Base URL for API requests (default:http://localhost:3000)msgpackUrl: ESM URL for the pinned MessagePack browser module (default:https://cdn.jsdelivr.net/npm/@msgpack/[email protected]/+esm)cors: Framework-neutral CORS config (translated by the server adapter, e.g.allowOrigin)rateLimit: Framework-neutral rate-limit config (translated by the server adapter, e.g.windowDurationMs,maxRequests)errorStatusCodes: map from error class name to HTTP status codemethod-rules: regex map for method resolution by function namemethod-rules-custom-functions: exact function name overrides for HTTP methodbinaryTypes: Type names considered binary (matched against TS types)
Setup
Use in your own project
Install in your app project:
npm install --save-dev proc2restThen run via npx (or npm exec):
npx proc2restOr add a script in your app's package.json:
{
"scripts": {
"generate-api": "proc2rest"
}
}Then run:
npm run generate-apiNote: local package binaries are available through npx/npm run and are located under node_modules/.bin.
A complete example project is available on GitHub: https://github.com/tobi2409/proc2rest/tree/main/examples/example1
Optional with explicit parameters:
npx proc2rest \
--appPath=. \
--srcServerDir=src/server \
--generatedServerDir=generated/srv \
--srcClientDir=src/client \
--generatedClientDir=generated/cl \
--configPath=proc2rest.config.jsonParameter overview:
--appPath: Root of your app project (default:.)--srcServerDir: Source directory for server TS files (default:src/server)--generatedServerDir: Output directory for generated server code (default:generated/server)--srcClientDir: Source directory for client JS files (default:src/client)--generatedClientDir: Output directory for generated client code (default:generated/client)--configPath: Path toproc2rest.config.json(default:<appPath>/proc2rest.config.json)
1. Install Dependencies
npm install2. Create Server Functions
In my-server.ts:
interface Person {
name: string
age: number
}
// @rest
export function getPerson(name: string): Person {
return { name, age: 30 }
}
// @rest
// @middleware(auth)
export function uploadFile(filename: string, data: Uint8Array): string {
return `${filename}: ${data.byteLength} bytes`
}3. Generate Code
npx proc2rest --appPath=examples/example1 --srcServerDir=src/server --generatedServerDir=generated/srv --srcClientDir=src/client --generatedClientDir=generated/clThis creates (u. a.):
examples/example1/generated/srv/routes.generated.ts- Express routesexamples/example1/generated/srv/logger.ts- Shared logger utility- copies of server source files from
src/server/**intogenerated/srv/** - generated API clients per configured server, e.g.
generated/cl/first/my-server-client.js - copied JS client source files from
src/client/**intogenerated/cl/** - injected imports in copied JS clients via
// @server-import <server-file.ts>markers
4. Start Server
cd examples/example1/generated/srv
npm install
npm startThe generated Express app listens on port 3000 by default (or $PORT).
5. Use Client in HTML
index.html:
<script type="module" src="index.js"></script>
<button id="btn">Get Person</button>src/client/index.js (source, with @server-import marker):
// @server-import first/my-server.ts
const { getPerson } = myServer
document.getElementById('btn').addEventListener('click', async () => {
const person = await getPerson('Jane Doe')
console.log(person)
})How It Works
HTTP Method Detection
The HTTP method is automatically derived from the function name prefix:
| Prefix | HTTP Method |
| ------------------------- | ----------- |
| get, list, find | GET |
| create, add, insert | POST |
| update, set, patch | PATCH |
| delete, remove | DELETE |
| (anything else) | POST |
Examples: getPerson → GET, addPerson → POST, deleteUser → DELETE.
Server Generation
- Parser (
exported-functions-metadata.js) usests-morphto extract function signatures - Only exported functions marked with
@restare mapped to routes - HTTP method is resolved from the function name (or custom overrides)
@middleware(nameA, nameB)markers are collected per route- Detects parameter types against
binaryTypesconfig - Generates appropriate middleware:
express.json()for JSON endpointsexpress.raw({ type: 'application/msgpack' })for binary endpoints
- Routes are created in
routes.generated.ts
Client Generation
- Uses metadata from configured
servers - Creates
<server-file>-client.jsfiles with ESM exports - Each function becomes an async API call:
- JSON endpoints:
JSON.stringify()request body - Binary endpoints:
MessagePack.encode()request body
- Injects imports into configured
jsClientsfrom// @server-import ...markers
Templates
- Generation uses Handlebars templates in adapter folders
{{...}}for escaped values,{{{...}}}for raw code insertion
Transport Formats
JSON (default):
await request(
'/api/myServer/getPerson',
'GET',
{ name: 'John' },
'application/json'
)MessagePack (for binary params):
const data = new Uint8Array([1, 2, 3])
await request(
'/api/myServer/uploadFile',
'POST',
{ filename: 'test', data },
'application/msgpack'
)Response handling is automatic—the client detects the response content-type and decodes accordingly.
@server-import Marker
In JS client files under src/client, add markers like:
// @server-import first/my-server.tsDuring generation, proc2rest replaces these markers with proper client imports.
Project Structure
proc2rest/
├── scripts/
│ ├── distro/
│ │ ├── express.js
│ │ ├── fetch.js
│ │ └── express-fetch.js
│ ├── generators/
│ │ ├── generate-server.js
│ │ ├── generate-client.js
│ │ ├── adapters/
│ │ │ ├── server/express-adapter/
│ │ │ └── client/fetch-adapter/
│ │ └── shared/
│ │ ├── exported-functions-metadata.js
│ │ ├── generator-config.js
│ │ └── cli-args.js
│ └── package.json
└── examples/
└── example1/
├── proc2rest.config.json
├── src/
│ ├── server/
│ └── client/
└── generated/Development
To regenerate after changes to server/client files:
npx proc2rest --appPath=examples/example1 --srcServerDir=src/server --generatedServerDir=generated/srv --srcClientDir=src/client --generatedClientDir=generated/clTo run the generated server:
cd examples/example1/generated/srv
npm install
npm startVS Code Setup
To prevent Live Server from reloading when server logs are written, add this to .vscode/settings.json:
{
"liveServer.settings.ignoreFiles": ["**/generated/srv/logs/**", "**/*.log"]
}Debugging MessagePack Requests
Add logging to client before sending:
const msgpack = await getMsgPackModule()
console.log('Sending:', params)
const encoded = msgpack.encode(params)
console.log('Encoded bytes:', encoded)Or inspect in browser DevTools → Network → binary request body.
Security Responsibilities
proc2rest provides basic transport-level safeguards such as Helmet integration, configurable CORS, rate limiting, request size limits, primitive parameter checks, generic client error responses, and server-side error logging. These mechanisms are not a complete application security layer.
Application developers remain responsible for:
- implementing authentication and authorization with appropriate middleware
- validating the structure, allowed values, and business rules of complex parameters; generated TypeScript assertions neither validate nor convert values at runtime
- using restrictive CORS settings instead of
allowOrigin: "*"where credentials or sensitive data are involved - configuring suitable rate limits and request size limits for every exposed endpoint
- terminating TLS/HTTPS securely, commonly through a reverse proxy, and applying secure deployment and network settings
- protecting secrets and sensitive data, and ensuring they are not exposed through source files, raw server code, responses, or logs
- reviewing all generated routes and trusted
rawServerFilesbefore deployment - keeping proc2rest, Express, middleware, and generated-server dependencies updated
- adding application-specific protections such as CSRF prevention, abuse protection, audit logging, and security monitoring where required
Generated endpoints should be treated like manually implemented public API endpoints and undergo the same security review and testing.
Limitations & TODOs
High Priority
- Unit tests for the generator: Test metadata extraction, HTTP method resolution, and code generation output
- HTTPS support: Allow configuring an HTTPS server (cert/key paths via config or CLI) in the generated server bootstrap
- Additional Express.js security mechanisms: Expand configurable hardening options beyond the existing Helmet, CORS, rate-limit, and request-size support
Medium Priority
- Filename patterns in config: Support glob patterns like
*.server.tsinstead of listing individual files
