{"id":13516547,"url":"https://github.com/evoluteur/evolutility-server-node","last_synced_at":"2026-03-06T08:02:11.672Z","repository":{"id":52154088,"uuid":"38994350","full_name":"evoluteur/evolutility-server-node","owner":"evoluteur","description":"Model-driven REST APIs for CRUD and more, written in Javascript, using Node.js, Express, and PostgreSQL.","archived":false,"fork":false,"pushed_at":"2024-03-17T06:56:01.000Z","size":790,"stargazers_count":112,"open_issues_count":1,"forks_count":33,"subscribers_count":24,"default_branch":"main","last_synced_at":"2025-03-04T22:32:56.867Z","etag":null,"topics":["crud","crud-api","crud-functionality","crud-operation","database","evolutility","low-code","mda","metadata","metadata-driven","model-driven-development","models","no-code","nodejs","orm","postgres","rest","rest-api","restful-api","sql"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evoluteur.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"evoluteur"}},"created_at":"2015-07-13T06:10:09.000Z","updated_at":"2024-12-06T07:49:48.000Z","dependencies_parsed_at":"2023-12-18T05:39:10.625Z","dependency_job_id":"b4e716e4-0005-4da4-b154-e47adf2be9da","html_url":"https://github.com/evoluteur/evolutility-server-node","commit_stats":{"total_commits":420,"total_committers":3,"mean_commits":140.0,"dds":0.004761904761904745,"last_synced_commit":"486d6193a6d8b0fb71fb80d77171a247e85d466a"},"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evoluteur%2Fevolutility-server-node","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evoluteur%2Fevolutility-server-node/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evoluteur%2Fevolutility-server-node/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evoluteur%2Fevolutility-server-node/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evoluteur","download_url":"https://codeload.github.com/evoluteur/evolutility-server-node/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244022645,"owners_count":20385135,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crud","crud-api","crud-functionality","crud-operation","database","evolutility","low-code","mda","metadata","metadata-driven","model-driven-development","models","no-code","nodejs","orm","postgres","rest","rest-api","restful-api","sql"],"created_at":"2024-08-01T05:01:23.396Z","updated_at":"2026-03-06T08:02:06.611Z","avatar_url":"https://github.com/evoluteur.png","language":"JavaScript","readme":"# Evolutility-Server-Node \u0026middot; [![GitHub license](https://img.shields.io/github/license/evoluteur/evolutility-server-node)](https://github.com/evoluteur/evolutility-server-node/blob/master/LICENSE.md) [![npm version](https://img.shields.io/npm/v/evolutility-server-node)](https://www.npmjs.com/package/evolutility-server-node)\n\n\nModel-driven REST API for CRUD and more, using Node.js, Express, and PostgreSQL.\n\nEvolutility-Server-Node provides a set of generic [REST APIs](#API) for CRUD (Create, Read, Update, Delete) and simple charts. on objects of different structures.\n\n![screenshot](https://raw.githubusercontent.com/evoluteur/evolutility-server-node/master/screenshot.png)\n\nFor a matching model-driven Web UI, use [Evolutility-UI-React](http://github.com/evoluteur/evolutility-ui-react) or [Evolutility-UI-jQuery](http://evoluteur.github.io/evolutility-ui-jquery/).\n\n\n### Table of Contents\n1. [Installation](#Installation)\n2. [Setup](#Setup)\n3. [Configuration](#Configuration)\n4. [Models](#Models): [Object](#Object) - [Field](#Field) - [Collection](#Collection) - [Sample model](#SampleModel)\n5. [REST API](#API): [Get](#API_Get) - [Update](#API_Update) - [Charts](#API_Charts) - [More](#API_Extras)\n6. [License](#License)\n\n\u003ca name=\"Installation\"\u003e\u003c/a\u003e\n## Installation\n\n[Download](https://github.com/evoluteur/evolutility-server-node/archive/master.zip) or clone from GitHub.\n\n```bash\n# To get the latest stable version, use git from the command line.\ngit clone https://github.com/evoluteur/evolutility-server-node\n```\nor use the [npm package](https://www.npmjs.com/package/evolutility-server-node):\n\n```bash\n# To get the latest stable version, use npm from the command line.\nnpm install evolutility-server-node\n```\n\nDependencies: [Node.js](https://nodejs.org/en/), [Express](http://expressjs.com/), [PostgreSQL](http://www.postgresql.org/), and [PG-Promise](https://github.com/vitaly-t/pg-promise).\n\nEvolutility-Server-Node works with **Node.js v12.12.0** (not yet compatible w/ later versions).\n\n\u003ca name=\"Setup\"\u003e\u003c/a\u003e\n## Setup\n\nAfter installing Evolutility-Server-Node, follow these steps:\n\n1. Create a PostgreSQL database.\n\n2. In the file [config.js](https://github.com/evoluteur/evolutility-server-node/blob/master/config.js) set the PostgreSQL connection string and the schema name to access your new database.\n\n3. Maybe, also change other config options in the same file.\n\n| Option     | Description        | Example            |\n|------------|--------------------|--------------------|\n| apiPath    | Path to REST API (can use \"proxy\" from package.json). | \"/api/v1/\" |\n| apiPort    | Port for the REST API. | 2000 |\n| connectionString  | Database connection string. | \"postgres://evol:love@localhost:5434/evolutility\" |\n| schema     | Database schema.        | \"evolutility\" |\n| uploadPath | Path to uploaded files. | \"../evolutility-ui-react/public/pix/\" |\n| apiInfo    | Enable API discovery (on root and per model). | true |\n| pageSize   | Page size in pagination.  | 50 |\n| lovSize    | Maximum number of items in list of values. | 100  |\n| csvSize    | Maximum number of items in CSV exports.    | 1000 |\n| csvHeader  | Use fields id or labels in CSV header.     | id/label |\n| locale     | Date format (no translation yet). | en/fr |\n| wTimestamp | Add timestamp columns \"created_at\" and \"updated_at\" to track record creation and update times. | true |\n| logToConsole | Log to console. | true |\n| logToFile    | Log to file (log file is named \"evol\u003ctimestamp\u003e.log\").    | true |\n\n4. In the command line type the following:\n\n```bash\n# Install dependencies\nnpm install\n\n# Create sample database w/ demo tables\nnpm run makedb\n\n# Run the node.js server\nnpm start\n\n```\n\n**Note**: The database creation and population scripts are logged in the files \"evol-db-schema-{datetime}.sql\" and  \"evol-db-data-{datetime}.sql\".\n\nURLs on localhost:\n\n- REST: [http://localhost:2000/api/v1/](http://localhost:2000/api/v1/)\n\n\n\u003ca name=\"Configuration\"\u003e\u003c/a\u003e\n## Configuration\n\nConfiguration options are set in the file [config.js](https://github.com/evoluteur/evolutility-server-node/blob/master/config.js).\n\n\n| Option        | Description                             |\n|---------------|-----------------------------------------|\n| apiPath       | Path for REST API (i.e.: \"/api/v1/\"). |\n| apiPort       | Port for REST API (i.e.: 2000). |\n| connectionString | DB connection string (i.e.: \"postgres://evol:love@localhost:5432/evol\"). |\n| schema        | DB schema name (i.e.: \"evolutility\").|\n| pageSize      | Number of rows per page in pagination (default = 50).|\n| lovSize       | Maximum number of values allowed for form dropdowns (default = 100). |\n| csvSize       | Maximum number of rows in CSV export (default = 1000).|\n| csvHeader     | CSV list of labels for CSV export| | uploadPath | path for pictures and documents uploads (i.e.: \"../evolutility-ui-react/public/pix/\").|\n| logToConsole    | Log SQL and errors to console.|\n| logToFile       | Log SQL and errors to a file. Log files are named like \"evol-2019-09-15.log\". |\n| wComments     | Allow for user comments (not implemented yet). |\n| wRating       | Allow for user ratings (not implemented yet). |\n| wTimestamp    | Timestamp columns w/ date of record creation and last update. |\n| createdDateColumn | Column containing created date (default \"created_at\"). |\n| updatedDateColumn | Column containing last update date (default \"updated_at\"). |\n| schemaQueries | Enables endpoints to query for lists of tables and columns in the database schema. |\n\n\u003ca name=\"Models\"\u003e\u003c/a\u003e\n## Models\n\nTo be accessible by the REST API, each database table must be described in a model.\nModels contain the name of the driving table and the list of fields/columns present in the API.\n\n- [Object](#Object)\n- [Field](#Field)\n- [Collection](#Collection)\n- [Sample model](#SampleModel)\n\n\n\u003ca name=\"Object\"\u003e\u003c/a\u003e\n### Object\n\n| Property     | Description                     |\n|--------------|---------------------------------|\n| id           | Unique key to identify the entity (used as API parameter). |\n| table        | Driving database table name (there are secondary tables for fields of type \"lov\"). |\n| pKey         | Name of the Primary key column (single column of type serial). Default to \"id\". In the data the key is always called \"id\". |\n| fields       | Array of fields.                        |\n| titleField   | Field id for the column value used as record title. |\n| noCharts     | No Charts or Dashboard views.   |\n| noStats      | No Stats on the object.         |\n\n\u003ca name=\"Field\"\u003e\u003c/a\u003e\n### Field\n\n| Property     | Description              |\n|--------------|--------------------------|\n| id           | Unique key for the field (can be the same as column but doesn't have to be). |\n| column       | Database column name for the field.    |\n| lovTable     | Table to join to for field value (only for fields of type \"lov\"). |\n| lovColumn    | Column name (in the lovTable) for field value (only for fields of type \"lov\"). |\n| lovIcon      | Set to True to include icon with LOV items (only for fields of type \"lov\").    |\n| object       | Model id for the object to link to (only for fields of type \"lov\").    |\n| type         | Field type is not a database column type but more a UI field type. Possible field types: \u003cul\u003e\u003cli\u003eboolean\u003c/li\u003e\u003cli\u003edate\u003c/li\u003e\u003cli\u003edatetime\u003c/li\u003e\u003cli\u003edecimal\u003c/li\u003e\u003cli\u003edocument\u003c/li\u003e\u003cli\u003eemail\u003c/li\u003e\u003cli\u003eimage\u003c/li\u003e\u003cli\u003einteger\u003c/li\u003e\u003cli\u003elov (list of values)\u003c/li\u003e\u003cli\u003elist (multiselect)\u003c/li\u003e\u003cli\u003emoney\u003c/li\u003e\u003cli\u003etext\u003c/li\u003e\u003cli\u003etextmultiline\u003c/li\u003e\u003cli\u003etime\u003c/li\u003e\u003cli\u003eurl\u003c/li\u003e\u003c/ul\u003e |\n| required     | Determines if the field is required for saving.      |\n| readOnly     | Display field as readOnly (not editable).            |\n| inMany       | Determines if the field is present (by default) in lists of records. |\n| inSearch     | Determine if the field is used in text searches.                     |\n| max, min     | Maximum/Minimum value allowed (only applies to numeric fields).      |\n| maxLength, minLength | Maximum/Minimum length allowed (only applies to text fields).|\n| unique       | Values must be unique (not implemented yet).   |\n| noCharts     | Exclude field from charts.      |\n| noStats      | Exclude field from Stats.       |\n| deleteTrigger | Deleting records in the lovTable will trigger a cascade delete (this property is only used while creating the database). |\n\n\n\u003ca name=\"Collection\"\u003e\u003c/a\u003e\n### Collection\n\nMultiple Master-Details can be specified with collections.\n\n| Property     | Meaning                  |\n|--------------|--------------------------|\n| id           | Unique key for the collection.        |\n| table        | DB Table to query (master table, other tables will be included in the query for \"lov\" fields). |\n| column       | Column in the detail table to match against id of object. |\n| object       | Model id for the object to display (optional).            |\n| orderBy      | Column(s) to sort by, e.g. { orderBy: \"name\" }.                 |\n| fields       | Array of fields (objects or ids). Fields in collections can be field objects or just ids of field in the collection's object.    |\n\nExample of collection in [Wine cellar](https://github.com/evoluteur/evolutility-server-node/blob/master/models/organizer/winecellar.js).\n\n\n\u003ca name=\"SampleModel\"\u003e\u003c/a\u003e\n### Sample model\n\nBelow is the model for a To-Do app.\n\n```javascript\nexport default {\n    id: \"todo\",\n    table: \"task\",\n    titleField: \"title\",\n    searchFields: [\"title\", \"duedate\", \"description\"],\n    fields: [\n        {\n            id: \"title\",\n            column: \"title\",\n            type: \"text\",\n            required: true,\n            inMany: true\n        },\n        {\n            id: \"duedate\",\n            column: \"duedate\",\n            type: \"date\",\n            inMany: true\n        },\n        {\n            id: \"category\",\n            column: \"category_id\",\n            type: \"lov\",\n            lovTable: \"task_category\",\n            inMany: true\n        },\n        {\n            id: \"priority\",\n            column: \"priority_id\",\n            type: \"lov\",\n            lovTable: \"task_priority\",\n            required: true,\n            inMany: true,\n        },\n        {\n            id: \"complete\",\n            column: \"complete\",\n            type: \"boolean\",\n            inMany: true\n        },\n        {\n            id: \"description\",\n            column: \"description\",\n            type: \"textmultiline\"\n        }\n    ]\n};\n\n```\n\nMore sample models:\n [Address book](https://github.com/evoluteur/evolutility-server-node/blob/master/models/organizer/contact.js),\n [Restaurants list](https://github.com/evoluteur/evolutility-server-node/blob/master/models/organizer/restaurant.js),\n [Wine cellar](https://github.com/evoluteur/evolutility-server-node/blob/master/models/organizer/winecellar.js),\n [Graphic novels inventory](https://github.com/evoluteur/evolutility-server-node/blob/master/models/organizer/comics.js).\n\nMore information about Evolutility models and some useful scripts are available at [evolutility-models](https://github.com/evoluteur/evolutility-models).\n\n\u003ca name=\"API\"\u003e\u003c/a\u003e\n## REST API\nEvolutility-Server-Node provides a generic RESTful API for CRUD (Create, Read, Update, Delete) and more. It is inspired from [PostgREST](http://postgrest.com).\n\n- [Get](#API_Get)\n- [Update](#API_Update)\n- [Charts](#API_Charts)\n- [More](#API_Extras)\n\nWhen running Evolutility-Server-Node locally, the base url is\n[http://localhost:2000/api/v1/](http://localhost:2000/api/v1/).\n\n\u003ca name=\"API_Get\"\u003e\u003c/a\u003e\n### Requesting Information\n\n#### Get One\nGets a specific record by ID.\n\n```\nGET /{model.id}/{id}\n\nGET /todo/12\n```\n\nBy default this endpoint returns nested collections with the record. For optimization, collections can be ommited by using the parameter \"shallow\".\n\n```\nGET /{model.id}/{id}?shallow=1\n\nGET /todo/12?shallow=1\n```\n\n#### Get Many\nGets a list of records.\n\n```\nGET /{model.id}\n\nGET /todo\n```\n\n\n\u003ca name=\"Filtering\"\u003e\u003c/a\u003e\n#### Filtering\nYou can filter result rows by adding conditions on fields, each condition is a query string parameter.\n\n```\nGET /{model.id}/{field.id}={operator}.{value}\n\nGET /todo?title=sw.a\nGET /todo?priority=in.1,2,3\n```\nAdding multiple parameters conjoins the conditions:\n\n```\ntodo?complete=0\u0026duedate=lt.2018-12-24\n```\n\nFor each field a sub-set of the operators below will be supported by the API (depending field types).\n\n| Operator     | Meaning                 | Example                      |\n|--------------|-------------------------|------------------------------|\n| eq           | equals                  | /todo?category=eq.1          |\n| gt           | greater than            | /todo?duedate=gt.2024-01-15  |\n| lt           | less than               | /todo?duedate=lt.2024-01-15  |\n| gte          | less than or equal      | /todo?duedate=gte.2024-01-15 |\n| lte          | less than or equal      | /todo?duedate=lte.2024-01-15 |\n| ct           | contains                | /todo?title=ct.e             |\n| sw           | start with              | /todo?title=sw.a             |\n| fw           | finishes with           | /todo?title=fw.z             |\n| in           | one of a list of values | /todo?priority=in.1,2,3      |\n| 0            | is false or null        | /todo?complete=0             |\n| 1            | is true                 | /todo?complete=1             |\n| null         | is null                 | /todo?category=null          |\n| nn           | is not null             | /todo?category==nn           |\n\n\n#### Searching\n\nYou can search for a specific string across multiple fields at once with the \"search\" parameter. The list of fields to be searched is specified with \"searchFields\" in the model (if unspecified, text fields flagged with \"inMany\" for list view will be used).\n\n```\nGET /{model.id}?search={value}\n\nGET /todo?search=translation\n```\n\n#### Ordering\n\nThe reserved word \"order\" reorders the response rows. It uses a comma-separated list of fields and directions:\n\n```\nGET /{model.id}?order={field.id}.{asc/desc}\n\nGET /todo?order=priority.desc,title.asc\n```\nIf no direction is specified it defaults to ascending order:\n```\nGET /todo?order=duedate\n```\n\n#### Limiting and Pagination\n\nThe reserved words \"page\" and \"pageSize\" limits the response rows.\n\n```\nGET /{model.id}?page={pageindex}\u0026pageSize={pagesize}\n\nGET /todo?page=0\u0026pageSize=50\n```\n\n#### Formatting\n\nBy default all APIs return data in JSON format. This API call allows to request data in CSV format (export to Excel).\nThis feature is using [csv-express](https://github.com/jczaplew/csv-express).\n\n```\nGET /{model.id}?format=csv\n\nGET /todo?format=csv\n```\nNotes: In the returned data every object has an extra property \"\\_full_count\" which indicate the total number of records in the query (before limit).\n\n\u003ca name=\"API_Update\"\u003e\u003c/a\u003e\n### Updating Data\n\n#### Record creation\n\nTo create a row in a database table post a JSON object whose keys are the names of the columns you would like to create. Missing keys will be set to default values when applicable.\n\n```\nPOST {model.id} {data}\n\nPOST /todo\n{ title: 'Finish testing', priority: 2}\n```\n\nEven though it is a \"POST\", the request also returns the newly created record. It is not standard but it saves the UI a subsequent call.\n\n#### Update\n\nPATCH or PUT can be used to update specific records.\n\n```\nPATCH /{model.id}/{id} {data}\n\nPATCH /todo/5\n{ title: 'Finish testing', priority: 2}\n```\n\n```\nPUT /{model.id}/{id} {data}\n\nPUT /todo/5\n{ title: 'Finish testing', priority: 2}\n```\n\nNotes: The request returns the updated record. It is not standard but it saves the UI a subsequent call.\n\n\n#### Deletion\nSimply use the DELETE verb with the id of the record to remove.\n\n```\nDELETE /{model.id}/{id}\n\nDELETE /todo/5\n```\n\nTo delete multiple records at once, pass multiple ids (separated by commas).\n\n```\nDELETE /{model.id}/{id1},{id2},{id3}\n\nDELETE /todo/5,7,12\n```\n\n\u003ca name=\"API_Extras\"\u003e\u003c/a\u003e\n### Extras endpoints\n\nIn addition to CRUD, Evolutility-Server-Node provides a few endpoints for Charts, Lists of values, file upload, and API discovery.\n\n#### Discovery\n\nReturns the list of all active objects with urls to their REST end-points.\n\n```\nGET /\n```\n\nIt is also possible to get a more detailed list of REST end-points for a specific model.\n\n```\nGET /?id={model.id}\n\nGET /?id=todo\nGET /?id=contact\n\n```\n\nNote: These end-point must be enabled in the configuration with { apiInfo: true }.\n\n\u003ca name=\"API_Charts\"\u003e\u003c/a\u003e\n#### Charts\n\nFor charts data, it is possible to get aggregated data for field of types lov, boolean, integer, decimal, and money. Use the attribute \"noCharts\" to exclude a field from Charts.\n\n```\nGET /{model.id}/chart/{field id}\n\nGET /todo/chart/category\n```\n\n#### Stats\n\nReturns the total count, and the min, max, average, variance, standard deviation and total for numeric fields in the model.\n\n```\nGET /{model.id}/stats\n\nGET /todo/stats\n```\n\n#### Lists of Values\n\nDropdown fields in the UI (field.type=\"lov\" in the model) have a REST endpoint to get the list of values. This endpoint can also take a search query parameter.\n\n```\nGET /{model.id}/lov/{field.id}\n\nGET /todo/lov/category\nGET /todo/lov/category?search=pro\n```\n\n#### File upload\n\nThis endpoint lets you upload a file. The current (naive) implementation simply saves the file on the file server in a folder named like the model id (inside the folder specified by the option \"uploadPath\" in config.js).\n\n```\nPOST /{model.id}/upload/{id}\n\nPOST /comics/upload/5\n```\n\nWith query parameters: file and \"field.id\".\n\n\n#### Nested collections\n\nIf the model has collections defined, they can be queried with this end-point.\n\n```\nGET /{model.id}/collec/{collection.id}?id={id}\n\nGET /winecellar/collec/wine_tasting?id=1\n```\n\n\u003ca name=\"Models\"\u003e\u003c/a\u003e\n#### Models\n\nWhen storing models in evol_object and evol_field tables, they can be queried through REST.\n\nGet all models flagged as active.\n\n```\nGET /meta/models\n```\n\nGet a model by ID (integer).\n\n```\nGET /meta/model/{modelid}\n\nGET /meta/model/1\n```\n\nNote: Schema and Models end-points must be enabled in the configuration with { apiDesigner: true }.\n\n#### Schema tables and columns\n\nThese endpoints query for the database structure (rather than the data), and returns lists of tables and columns.\n\nList of schema tables (props: table, type, readOnly).\n\n```\nGET /db/tables\n```\n\nList of columns (props: column, type, required) for a specified table.\n\n```\nGET /db/{table_name}/columns\n\nGET /db/contact/columns\nGET /db/task/columns\n```\n\nNote: These end-point must be enabled in the configuration with { schemaQueries: true }.\n\n#### API version\n\nThis endpoint gets the API version (as specified in the project's package.json file).\n\n```\nGET /version\n```\n\n\u003ca name=\"License\"\u003e\u003c/a\u003e\n## License\n\nCopyright (c) 2024 [Olivier Giulieri](https://evoluteur.github.io/).\n\nEvolutility-Server-Node is released under the [AGPLv3 license](http://github.com/evoluteur/evolutility-server-node/blob/master/LICENSE.md).\n","funding_links":["https://github.com/sponsors/evoluteur"],"categories":["JavaScript","database"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevoluteur%2Fevolutility-server-node","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevoluteur%2Fevolutility-server-node","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevoluteur%2Fevolutility-server-node/lists"}