{"library":"odata4-server","title":"OData V4 Server for Node.js","description":"odata4-server is an abandoned Node.js library for creating OData V4 compliant servers, originally forked from the equally unmaintained `jaystack/odata-v4-server`. It provides a decorator-driven approach to define OData controllers and expose service metadata (`$metadata`), supporting a wide range of OData query language features like filtering (`$filter`), sorting (`$orderby`), paging (`$skip`, `$top`), projection (`$select`), and expansion (`$expand`). It can operate as a standalone server, an Express router, or a Node.js stream. The package is currently at version 0.3.0, with its last update more than seven years ago (as of April 2026), indicating it is no longer actively maintained. Due to its abandoned status, it's not recommended for new projects or production use.","language":"javascript","status":"abandoned","last_verified":"Wed Apr 22","install":{"commands":["npm install odata4-server"],"cli":null},"imports":["import { ODataServer } from 'odata4-server'","import { ODataController } from 'odata4-server'","import * as odata from 'odata4-server'"],"auth":{"required":false,"env_vars":[]},"quickstart":{"code":"import { createFilter, ODataController, ODataServer, ODataQuery } from 'odata4-server';\nimport * as odata from 'odata4-server';\n\n// Mock data for demonstration\ninterface Product { _id: string; name: string; categoryId: string; }\ninterface Category { _id: string; name: string; }\n\nconst products: Product[] = [\n  { _id: '1', name: 'Apples', categoryId: 'cat1' },\n  { _id: '2', name: 'Bananas', categoryId: 'cat1' },\n  { _id: '3', name: 'Carrots', categoryId: 'cat2' }\n];\n\nconst categories: Category[] = [\n  { _id: 'cat1', name: 'Fruits' },\n  { _id: 'cat2', name: 'Vegetables' }\n];\n\n// Simple unique ID generator (replace with proper DB IDs in real app)\nlet nextId = 10;\nconst generateId = () => (nextId++).toString();\n\n@odata.controller(products, 'Products')\nexport class ProductsController extends ODataController{\n    @odata.GET\n    find(@odata.filter filter: ODataQuery) {\n        console.log('GET /Products', filter);\n        if (filter) return products.filter(createFilter(filter));\n        return products;\n    }\n\n    @odata.GET\n    findOne(@odata.key key: string) {\n        console.log(`GET /Products(${key})`);\n        return products.filter(product => product._id === key)[0];\n    }\n\n    @odata.POST\n    insert(@odata.body product: any) {\n        console.log('POST /Products', product);\n        product._id = generateId();\n        products.push(product);\n        return product;\n    }\n\n    @odata.PATCH\n    update(@odata.key key: string, @odata.body delta: any) {\n        console.log(`PATCH /Products(${key})`, delta);\n        let product = products.filter(product => product._id === key)[0];\n        if (product) {\n            for (let prop in delta) {\n                if (Object.prototype.hasOwnProperty.call(delta, prop)) {\n                    (product as any)[prop] = delta[prop];\n                }\n            }\n        }\n    }\n\n    @odata.DELETE\n    remove(@odata.key key: string) {\n        console.log(`DELETE /Products(${key})`);\n        const index = products.findIndex(product => product._id === key);\n        if (index > -1) {\n            products.splice(index, 1);\n        }\n    }\n}\n\n@odata.controller(categories, 'Categories')\nexport class CategoriesController extends ODataController{\n    @odata.GET\n    find(@odata.filter filter:ODataQuery) {\n        console.log('GET /Categories', filter);\n        if (filter) return categories.filter(createFilter(filter));\n        return categories;\n    }\n\n    @odata.GET\n    findOne(@odata.key key:string) {\n        console.log(`GET /Categories(${key})`);\n        return categories.filter(category => category._id === key)[0];\n    }\n\n    @odata.POST\n    insert(@odata.body category:any) {\n        console.log('POST /Categories', category);\n        category._id = generateId();\n        categories.push(category);\n        return category;\n    }\n\n    @odata.PATCH\n    update(@odata.key key:string, @odata.body delta:any) {\n        console.log(`PATCH /Categories(${key})`, delta);\n        let category = categories.filter(category => category._id === key)[0];\n        if (category) {\n            for (let prop in delta) {\n                if (Object.prototype.hasOwnProperty.call(delta, prop)) {\n                    (category as any)[prop] = delta[prop];\n                }\n            }\n        }\n    }\n\n    @odata.DELETE\n    remove(@odata.key key:string) {\n        console.log(`DELETE /Categories(${key})`);\n        const index = categories.findIndex(category => category._id === key);\n        if (index > -1) {\n            categories.splice(index, 1);\n        }\n    }\n}\n\n@odata.cors\n@odata.controller(ProductsController, true)\n@odata.controller(CategoriesController, true)\nexport class NorthwindODataServer extends ODataServer{}\n\nconst PORT = process.env.PORT || 3000;\nNorthwindODataServer.create('/odata', PORT);\nconsole.log(`OData server listening on http://localhost:${PORT}/odata`);\nconsole.log(`Access metadata at http://localhost:${PORT}/odata/$metadata`);\nconsole.log(`Try: http://localhost:${PORT}/odata/Products?$filter=name eq 'Apples'`);\nconsole.log(`Try: http://localhost:${PORT}/odata/Categories('cat1')`);\n","lang":"typescript","description":"This quickstart sets up a basic OData V4 server with two entity sets, 'Products' and 'Categories', demonstrating CRUD operations and OData query capabilities using decorators. It includes mock data and logs requests to the console, listening on port 3000 by default. Requires TypeScript compilation with decorator support.","tag":null,"tag_description":null,"last_tested":null,"results":[]},"compatibility":null}