odoo-json-rpc-client
v1.0.0
Published
A fully typed TypeScript JSON-RPC client for Odoo's External API
Maintainers
Readme
odoo-json-rpc-client
A fully typed TypeScript JSON-RPC client for Odoo's External API.
Features
- ✅ Full TypeScript support with precise type definitions
- 🔒 Type-safe CRUD operations (search, read, create, write, unlink)
- 🚀 Promise-based API for modern async/await syntax
- 🔧 Flexible configuration with custom timeouts, debug mode, and HTTP agents
- 📦 Zero dependencies (axios as peer dependency)
- ✨ 100% test coverage
- 🌐 Compatible with Node.js and potentially Expo Go (with limitations)
Installation
npm install odoo-json-rpc-client axiosor with yarn:
yarn add odoo-json-rpc-client axiosor with pnpm:
pnpm add odoo-json-rpc-client axiosQuick Start
import { OdooClient } from 'odoo-json-rpc-client';
const client = new OdooClient({
url: 'https://your-odoo-instance.com',
db: 'your-database',
login: 'your-username',
password: 'your-password',
});
// Authenticate
const uid = await client.authenticate();
if (!uid) throw new Error('Authentication failed');
// Get server version
const version = await client.version();
console.log('Odoo version:', version.server_version);
// Search for company partners
const partnerIds = await client.search('res.partner', [
['is_company', '=', true]
], { limit: 10 });
// Read partner data with type safety
interface Partner {
id: number;
name: string;
email: string;
}
const partners = await client.read<Partner>(
'res.partner',
partnerIds,
['id', 'name', 'email']
);
console.log('Partners:', partners);Configuration
Basic Configuration
const client = new OdooClient({
url: 'https://your-odoo-instance.com',
db: 'your-database',
login: 'your-username',
password: 'your-password',
});Advanced Configuration
import https from 'https';
const client = new OdooClient({
url: 'https://your-odoo-instance.com',
db: 'your-database',
login: 'your-username',
password: 'your-password',
options: {
// Enable debug logging (logs all requests/responses)
debug: true,
// Set custom timeout (default: 3000ms)
timeoutMs: 5000,
// Use custom HTTPS agent (Node.js only)
// Useful for self-signed certificates, proxies, or keep-alive
agent: new https.Agent({
rejectUnauthorized: false, // Accept self-signed certificates
keepAlive: true,
}),
},
});API Reference
Authentication
authenticate(reqId?: number): Promise<number | false>
Authenticates the user and retrieves the user ID (uid).
const uid = await client.authenticate();
if (uid) {
console.log('Authenticated as user', uid);
} else {
console.log('Authentication failed');
}isAuthenticated(): boolean
Check if the client is authenticated.
if (client.isAuthenticated()) {
console.log('User ID:', client.getUid());
}getUid(): number | false
Returns the current user ID or false if not authenticated.
Server Information
version(reqId?: number): Promise<OdooVersionInfo>
Retrieves Odoo server version information. No authentication required.
const version = await client.version();
console.log('Server version:', version.server_version);
console.log('Protocol version:', version.protocol_version);Generic Method Execution
executeKw<T>(model: string, method: string, args: any[], kwargs?: Record<string, any>, reqId?: number): Promise<T>
Execute any Odoo model method with full type safety.
// Custom method call with type safety
const result = await client.executeKw<number>(
'res.partner',
'name_search',
['Acme'],
{ limit: 5 }
);CRUD Operations
search(model: string, domain: any[], kwargs?: Record<string, any>, reqId?: number): Promise<number[]>
Search for record IDs matching the domain criteria.
const ids = await client.search('res.partner', [
['is_company', '=', true],
['country_id.code', '=', 'US']
], {
limit: 100,
offset: 0,
order: 'name ASC'
});searchCount(model: string, domain: any[], kwargs?: Record<string, any>, reqId?: number): Promise<number>
Count records matching the domain criteria.
const count = await client.searchCount('res.partner', [
['is_company', '=', true]
]);
console.log('Total companies:', count);read<T>(model: string, ids: number[], fields?: string[], kwargs?: Record<string, any>, reqId?: number): Promise<T[]>
Read records by IDs with optional field selection.
interface Partner {
id: number;
name: string;
email: string;
phone: string;
}
const partners = await client.read<Partner>(
'res.partner',
[1, 2, 3],
['id', 'name', 'email', 'phone']
);searchRead<T>(model: string, domain: any[], fields?: string[], kwargs?: Record<string, any>, reqId?: number): Promise<T[]>
Combined search and read in a single call.
const partners = await client.searchRead<Partner>(
'res.partner',
[['is_company', '=', true]],
['id', 'name', 'email'],
{ limit: 50 }
);create(model: string, values: Record<string, any>, kwargs?: Record<string, any>, reqId?: number): Promise<number>
Create a new record and return its ID.
const partnerId = await client.create('res.partner', {
name: 'New Company',
email: '[email protected]',
is_company: true,
});
console.log('Created partner ID:', partnerId);write(model: string, ids: number[], values: Record<string, any>, kwargs?: Record<string, any>, reqId?: number): Promise<true>
Update existing records. Returns true on success.
const success = await client.write('res.partner', [1, 2], {
phone: '+1234567890',
});
console.log('Update successful:', success);unlink(model: string, ids: number[], kwargs?: Record<string, any>, reqId?: number): Promise<true>
Delete records. Returns true on success.
const success = await client.unlink('res.partner', [123, 124]);
console.log('Delete successful:', success);Model Introspection
fieldsGet(model: string, attributes?: string[], kwargs?: Record<string, any>, reqId?: number): Promise<any>
Get field definitions for a model.
const fields = await client.fieldsGet('res.partner', ['string', 'type', 'required']);
console.log('Partner fields:', fields);Static Methods
OdooClient.getNextReqId(): number
Get the next request ID for manual request tracking.
const reqId = OdooClient.getNextReqId();
const version = await client.version(reqId);Error Handling
The client provides custom error classes for better error handling:
import {
OdooClient,
OdooError,
InvalidJsonRpcVersionError,
MismatchedRequestIdError,
} from 'odoo-json-rpc-client';
try {
const partners = await client.search('res.partner', []);
} catch (error) {
if (error instanceof OdooError) {
console.error('Odoo error:', error.message);
console.error('Error code:', error.code);
console.error('Error data:', error.data);
} else if (error instanceof InvalidJsonRpcVersionError) {
console.error('Invalid JSON-RPC version:', error.receivedVersion);
} else if (error instanceof MismatchedRequestIdError) {
console.error('Request ID mismatch:', error.expectedId, error.receivedId);
} else {
console.error('Unknown error:', error);
}
}TypeScript Support
This library is written in TypeScript and provides full type definitions. You can leverage TypeScript's type system for better IDE support and type safety:
// Define your model interface
interface SaleOrder {
id: number;
name: string;
partner_id: [number, string];
amount_total: number;
state: 'draft' | 'sent' | 'sale' | 'done' | 'cancel';
}
// Use it with type safety
const orders = await client.searchRead<SaleOrder>(
'sale.order',
[['state', '=', 'sale']],
['id', 'name', 'partner_id', 'amount_total', 'state']
);
// TypeScript will enforce the type
orders.forEach(order => {
console.log(order.name); // OK
console.log(order.invalid); // TypeScript error
});Examples
Check the examples folder for more usage examples:
- Basic Usage - Simple CRUD operations
- Authentication - Authentication examples
- Version Info - Getting server version
- Search & Count - Searching and counting records
- Search & Read - Combined search and read
- Create, Write, Unlink - Record manipulation
- Introspection - Model field inspection
Platform Compatibility
Node.js ✅
Fully supported with all features including custom HTTP/HTTPS agents.
Browsers ⚠️
Should work in browsers, but the agent option is not supported (Node.js only).
React Native / Expo Go ⚠️
Compatible with basic functionality. The agent option is not supported in React Native/Expo environments.
Development
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Build the project
npm run build
# Watch mode for development
npm run devContributing
Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.
License
This project is licensed under the MIT License - see the LICENSE file for details.
References
⚠️ Important: Odoo has announced that JSON-RPC support will be removed starting from Odoo 20. For new integrations, it is recommended to use the new REST or GraphQL APIs provided by Odoo. See the Odoo External API Documentation for more details.
Support
If you encounter any issues or have questions, please:
- Check the examples folder
- Review the API documentation
- Open an issue on GitHub
Author
Copyright (c) 2025 Robin Lamotte
Changelog
See CHANGELOG.md for version history and updates.
