OData V4 Server for Node.js

0.2.13 · maintenance · verified Sun Apr 19

odata-v4-server is a Node.js library for building OData Version 4.0 compliant servers. It allows developers to expose OData services either as a standalone server, an Express router, or as a stream. The package facilitates defining service metadata using TypeScript decorators or a JSON schema, supporting standard OData features like query language parsing ($filter, $orderby, $top, $skip, $select, $expand, $count) and CRUD operations on entity sets. It also supports complex types, navigation properties, actions, and functions. Currently at version 0.2.13, its release cadence appears to be irregular as it's still in pre-1.0 development. A key differentiator is its extensive use of decorators for defining controllers and handling OData query parameters, streamlining the development of data services.

Common errors

Warnings

Install

Imports

Quickstart

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));

view raw JSON →