Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslnode 18–226 runs
build_error
glibcnode 18–226 runs
build_error
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
ODataServer
✓ import { ODataServer } from 'odata-v4-server';
✗ const { ODataServer } = require('odata-v4-server');
The library primarily uses ES Module syntax and TypeScript decorators. While CJS might work in some setups, ESM is the intended and idiomatic way.
ODataController
✓ import { ODataController } from 'odata-v4-server';
✗ import ODataController from 'odata-v4-server';
This is a named export. Ensure to use destructuring `{ ODataController }`.
odata
✓ import * as odata from 'odata-v4-server';
✗ import { odata } from 'odata-v4-server';
The 'odata' object contains all decorators like `@odata.GET`, `@odata.controller`, `@odata.key`. It's typically imported as a namespace.
ODataQuery
✓ import { ODataQuery } from 'odata-v4-server';
This type is used for annotating parameters that receive parsed OData query expressions, such as in `@odata.filter`.
This quickstart demonstrates how to set up a basic OData V4 server with two controllers (Products and Categories) handling standard CRUD operations, using TypeScript decorators for routing and parameter injection. It includes a minimal data store simulation and server initialization.
import { ODataController, ODataServer, odata, ODataQuery } from 'odata-v4-server';
import { MongoClient, ObjectId } from 'mongodb'; // Assuming MongoDB for example persistence
// Dummy data for demonstration
const products: any[] = [];
const categories: any[] = [];
// Helper to create a filter function (simplified for example)
const createFilter = (filter: ODataQuery) => (item: any) => {
// In a real application, you'd parse ODataQuery to build a robust filter predicate.
// This is a placeholder.
console.warn('Filter parsing in createFilter is simplified for demonstration.');
return true;
};
export class ProductsController extends ODataController {
@odata.GET
find(@odata.filter filter: ODataQuery) {
if (filter) return products.filter(createFilter(filter));
return products;
}
@odata.GET
findOne(@odata.key key: string) {
return products.find(product => product._id === key);
}
@odata.POST
insert(@odata.body product: any) {
product._id = new ObjectId().toHexString(); // Simulate MongoDB ID
products.push(product);
return product;
}
@odata.PATCH
update(@odata.key key: string, @odata.body delta: any) {
let product = products.find(product => product._id === key);
if (product) {
Object.assign(product, delta);
}
}
@odata.DELETE
remove(@odata.key key: string) {
const index = products.findIndex(product => product._id === key);
if (index > -1) {
products.splice(index, 1);
}
}
}
export class CategoriesController extends ODataController {
@odata.GET
find(@odata.filter filter: ODataQuery) {
if (filter) return categories.filter(createFilter(filter));
return categories;
}
@odata.GET
findOne(@odata.key key: string) {
return categories.find(category => category._id === key);
}
@odata.POST
insert(@odata.body category: any) {
category._id = new ObjectId().toHexString();
categories.push(category);
return category;
}
@odata.PATCH
update(@odata.key key: string, @odata.body delta: any) {
let category = categories.find(category => category._id === key);
if (category) {
Object.assign(category, delta);
}
}
@odata.DELETE
remove(@odata.key key: string) {
const index = categories.findIndex(category => category._id === key);
if (index > -1) {
categories.splice(index, 1);
}
}
}
@odata.cors
@odata.controller(ProductsController, true)
@odata.controller(CategoriesController, true)
export class NorthwindODataServer extends ODataServer {}
// Initialize some dummy data
products.push({ _id: new ObjectId().toHexString(), name: 'Product A', price: 10, categoryId: 'cat1' });
categories.push({ _id: 'cat1', name: 'Category X' });
console.log('Starting OData server on port 3000 at /odata...');
NorthwindODataServer.create('/odata', 3000).then(() => {
console.log('OData server started. Try accessing:');
console.log(' http://localhost:3000/odata');
console.log(' http://localhost:3000/odata/$metadata');
console.log(' http://localhost:3000/odata/Products');
console.log(' http://localhost:3000/odata/Products(\'<product_id>\')');
}).catch(err => console.error('Failed to start OData server:', err));
Errors
Common errors & fixes
ReferenceError: Reflect is not defined
Missing `reflect-metadata` polyfill or incorrect `tsconfig.json` settings for decorators.
fixInstall `reflect-metadata` (`npm i reflect-metadata`) and import it once at the entry point of your application (`import 'reflect-metadata';`). Also, ensure `"emitDecoratorMetadata": true` is set in `tsconfig.json`.
error TS2307: Cannot find module 'odata-v4-server' or its corresponding type declarations.
Package not installed, or TypeScript cannot find its declaration files.
fixEnsure `odata-v4-server` is installed (`npm i odata-v4-server`). If using an older TypeScript version or complex project setup, verify `node_modules/@types/odata-v4-server` (if it existed) or `node_modules/odata-v4-server/dist/index.d.ts` is correctly resolved by your `tsconfig.json`.
Error: Decorators are not enabled. You must enable them in your TypeScript configuration (experimentalDecorators: true).
`experimentalDecorators` is not enabled in `tsconfig.json`.
fixAdd `"experimentalDecorators": true` to the `"compilerOptions"` section of your `tsconfig.json`.
TypeError: Cannot read properties of undefined (reading 'create')
Trying to call `ODataServer.create` without ensuring `NorthwindODataServer` extends `ODataServer` and is correctly decorated, or a transpilation issue.
fixVerify that your server class properly `extends ODataServer` and that all decorators (`@odata.controller`, `@odata.cors`) are applied and transpiled correctly. Ensure `reflect-metadata` is imported at the top of your entry file.
Audit
Dependencies
odata-v4-parserrequiredRequired for parsing OData query language expressions like $filter and $orderby.
odata-v4-service-metadataoptionalNeeded if setting up metadata via JSON instead of decorators.