{"id":36502492,"url":"https://github.com/dividedbyzeroco/warp-server","last_synced_at":"2026-01-12T02:24:58.380Z","repository":{"id":57163973,"uuid":"58519030","full_name":"dividedbyzeroco/warp-server","owner":"dividedbyzeroco","description":"ORM for the scalable web","archived":false,"fork":false,"pushed_at":"2018-12-02T16:27:48.000Z","size":1422,"stargazers_count":9,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-24T15:55:47.722Z","etag":null,"topics":["database","middleware","mysql","nodejs","orm","warp"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dividedbyzeroco.png","metadata":{"files":{"readme":"readme-legacy.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-05-11T06:17:35.000Z","updated_at":"2021-07-12T05:53:41.000Z","dependencies_parsed_at":"2022-09-04T00:41:09.741Z","dependency_job_id":null,"html_url":"https://github.com/dividedbyzeroco/warp-server","commit_stats":null,"previous_names":["jakejosol/warp-server"],"tags_count":221,"template":false,"template_full_name":null,"purl":"pkg:github/dividedbyzeroco/warp-server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dividedbyzeroco%2Fwarp-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dividedbyzeroco%2Fwarp-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dividedbyzeroco%2Fwarp-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dividedbyzeroco%2Fwarp-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dividedbyzeroco","download_url":"https://codeload.github.com/dividedbyzeroco/warp-server/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dividedbyzeroco%2Fwarp-server/sbom","scorecard":{"id":345308,"data":{"date":"2025-08-11","repo":{"name":"github.com/dividedbyzeroco/warp-server","commit":"e586e7695eef92a7c886e135f42df93c5bad2ee8"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.3,"checks":[{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"40 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-6chw-6frg-f759","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-qwcr-r2fm-qrc7","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-rv95-896h-c2vc","Warn: Project is vulnerable to: GHSA-qw6h-vgh9-j6wx","Warn: Project is vulnerable to: GHSA-4q6p-r6v2-jvc5","Warn: Project is vulnerable to: GHSA-2pr6-76vf-7546","Warn: Project is vulnerable to: GHSA-8j8c-7jfh-h6hx","Warn: Project is vulnerable to: GHSA-4xc9-xhrj-v574","Warn: Project is vulnerable to: GHSA-x5rq-j2xg-h7qm","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-8hfj-j24r-96c4","Warn: Project is vulnerable to: GHSA-wc69-rhjr-hc9g","Warn: Project is vulnerable to: GHSA-56x4-j7p9-fcf9","Warn: Project is vulnerable to: GHSA-v78c-4p63-2j6c","Warn: Project is vulnerable to: GHSA-3j8f-xvm3-ffx4","Warn: Project is vulnerable to: GHSA-4p35-cfcx-8653","Warn: Project is vulnerable to: GHSA-7f3x-x4pr-wqhj","Warn: Project is vulnerable to: GHSA-jpp7-7chh-cf67","Warn: Project is vulnerable to: GHSA-q6wq-5p59-983w","Warn: Project is vulnerable to: GHSA-j9fq-vwqv-2fm2","Warn: Project is vulnerable to: GHSA-pqw5-jmp5-px4v","Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j","Warn: Project is vulnerable to: GHSA-rhx6-c78j-4q9w","Warn: Project is vulnerable to: GHSA-g6ww-v8xp-vmwg","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg","Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T06:54:35.395Z","repository_id":57163973,"created_at":"2025-08-18T06:54:35.395Z","updated_at":"2025-08-18T06:54:35.395Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28332295,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T00:36:25.062Z","status":"online","status_checked_at":"2026-01-12T02:00:08.677Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["database","middleware","mysql","nodejs","orm","warp"],"created_at":"2026-01-12T02:24:58.312Z","updated_at":"2026-01-12T02:24:58.374Z","avatar_url":"https://github.com/dividedbyzeroco.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Warp Server\n===========\n\n__Warp Server__ is an `express` middleware for implementing scalable backend services. With Warp Server, you can store and manage data, call functions and run background processes using a simple REST API.\n\nCurrently, `Warp Server` uses `mysql`/`mariadb` as its database of choice, but can be extended to use other data storage providers.\n\n## Table of Contents\n- **[Installation](#installation)**  \n- **[Configuration](#configuration)**\n- **[Models](#models)**\n    - **[Pointers](#pointers)**\n    - **[Files](#files)**\n    - **[User Authentication](#user-authentication)**\n    - **[Using Model Directories](#using-model-directories)**\n- **[Migrations](#migrations)**\n- **[Functions](#functions)**\n- **[Queues](#queues)**\n\n## Other Resources\n- **Communicating with the Server**\n    - [Using the REST API](rest.md)\n    - [Using the JavaScript SDK](http://github.com/dividedbyzeroco/warp-sdk-js)\n    - Using the Android SDK (coming soon)\n    - Using the iOS SDK (coming soon)\n    - Using the Xamarin SDK (coming soon)\n- **Command Line Tools**\n    - [Warp Tools for the Command Line](http://github.com/dividedbyzeroco/warp-tools)\n- **References**\n    - [References (Errors, Models, etc.)](references.md)\n\n## Installation\n\nTo install Warp Server via npm, simply use the install command to save it in your package.json:\n\n```javascript\nnpm install --save warp-server\n```\n\n## Configuration\n\nWarp Server is built on top of `express` and can be initialized in any `express` project. To do so, simply add the following configruation to the main file of your project:\n\n```javascript\n// References\nvar express = require('express');\nvar WarpServer = require('warp-server');\n\n// Prepare config; You can also use process.env or store the config in a json file\nvar config = {\n    security: {\n        apiKey: '12345678abcdefg',\n        masterKey: 'abcdefg12345678'\n    },\n    database: {\n        host: 'localhost',\n        port: 3306,\n        user: 'root',\n        password: 'password',\n        default: 'default_database',\n        timeout: 3000, // OPTIONAL\n        charset: 'utf8mb4_unicode_ci', // OPTIONAL\n        persistentConnections: true // OPTIONAL, indicate whether pool connections should just be released, or destroyed,\n    },\n    throttle: {\n        limit: 5, // Default throttle number is 20 if not assigned.\n    }\n};\n\n// Create a new Warp Server API\nvar api = new WarpServer(config);\n\n// Apply the Warp Server router to your preferred base URL, using express' app.use() method\nvar app = express();\napp.use('/api/1', api.router());\n```\n\n## Models\n\nModels make it easy to define the tables found in the database. They contain special parameters which allow you to control the data that comes in and out of the server.\n\nTo define a Model, simply create a `WarpServer.Model` class with the following parameters:\n\n```javascript\nWarpServer.Model.create({\n    // Unique name assigned to the endpoint; is usally the same as the table name\n    className: '{CLASS_NAME}',\n    \n    // If the assigned className is not the same as the table name, specify the real table name here, OPTIONAL\n    source: '{SOURCE}',\n    \n    // Define keys/fields available in the table\n    keys: {\n        viewable: ['{KEY1}', '{KEY2}', '{KEY3}'], // REQUIRED: Fields viewable in queries\n        actionable: ['{KEY1}', '{KEY2}', '{KEY3}'], // REQUIRED: Fields editable in queries\n        \n        // To define pointers (i.e. foreign key relations), declare them via the `pointers` option, OPTIONAL\n        // For more info, please see section on Pointers\n        pointers: {\n            '{KEY2}': {\n                className: '{CLASS_NAME_OF_POINTER}',\n                via: '{FOREIGN_KEY}' // OPTIONAL, if `via` is not set, it is assumed to be `className`_id\n            }\n        },\n        \n        // To define file keys (i.e. fields for storing file URL's), declare them via the `files` option, OPTIONAL\n        // For more info, please see section on Files\n        files: ['{KEY3']\n    },\n    \n    // Validates values that are sent to the server\n    validate: {\n        // User-defined validation\n        '{KEY1}': function(value, key) {\n            // Some validations placed here\n            // If the validations fail, return a string message\n            return 'Validation failed for ' + key;\n            // If the validations succeed, return nothing\n            return;\n        },\n        // Pre-defined Validation; See section on Pre-defined Validations for more info\n        '{KEY2}': WarpServer.Model.Validation.FixedString(8)\n    },\n    \n    // Parses the values received, and pushes them to the backend for saving\n    parse: {\n        // User-defined parser\n        '{KEY1}': function(value) {\n            // Conduct some changes to the value, as needed;\n            // Return the parsed value\n            return value;\n        },\n        // Pre-defined Parser; See section on Pre-defined Parsers for more info\n        '{KEY2}': WarpServer.Model.Parser.Integer\n    },\n    \n    // Formats the values requested, and pushes them to the response\n    format: {\n        // User-defined formatter\n        '{KEY1}': function(value) {\n            // Conduct some changes to the value, as needed;\n            // Return the formatted value\n            return value;\n        },\n        // Pre-defined Formatter; See section on Pre-defined Formatters for more info\n        '{KEY2}': WarpServer.Model.Parser.Date\n    },\n    \n    // Function that manipulates the keys' values before the values are saved\n    beforeSave: function(request, response) {\n        // this.validate doesn't apply here\n        // this.parse doesn't apply here\n        \n        // Check if Object has just been newly created\n        if(request.isNew)\n            return; // Apply some logic here\n            \n        // Check if Object has just been recently destroyed\n        if(request.isDestroyed)\n            return; // Apply some logic here\n\n        // Check the client SDK performing the request (e.g. REST, Android, iOS,)\n        var client = request.client;\n\n        // Check the SDK version of the client request\n        var sdkVersion = request.sdkVersion;\n\n        // Check the version of the app that made the request\n        var appVersion = request.appVersion;\n        \n        // request.keys is a map that contains the modified keys of the object\n        request.keys.set('{KEY1}', '{VALUE1}');\n        var key2 = request.keys.get('{KEY2}');\n        \n        // Call the success response after the keys have been manipulated\n        if(success)\n            response.success();\n        else\n            // Or call the error response if an error has been encountered\n            response.error(error);\n    },\n    \n    // Function that executes after the values are saved\n    afterSave: function(request) {\n        // this.validate doesn't apply here\n        // this.parse doesn't apply here\n        \n        // Check if Object has just been newly created\n        if(request.isNew)\n            return; // Apply some logic here\n            \n        // Check if Object has just been recently destroyed\n        if(request.isDestroyed)\n            return; // Apply some logic here\n        \n        // request.keys is a map that contains the modified keys of the object\n        request.keys.set('{KEY1}', '{VALUE1}');\n        var key2 = request.keys.get('{KEY2}');\n    }\n});\n```\n\nFor example, if we want to make a model for an `alien` table, we can write it as:\n\n```javascript\nvar Alien = WarpServer.Model.create({\n    className: 'alien',\n    keys: {\n        viewable: ['name', 'age', 'type'],\n        actionable: ['name', 'age', 'type']\n    },\n    validate: {\n        'name': function(value) {\n            if(value.length \u003c 8) return 'name must be 8 or more characters';\n            return;\n        },\n        'age': WarpServer.Model.Validation.PositiveInteger\n    },\n    parse: {\n        'age': WarpServer.Model.Parser.Integer,\n        'type': function(value) {\n            switch(value)\n            {\n                case 0: return 'dalek';\n                case 1: return 'cyberman';\n                case 2: return 'zygon';\n                case 3: return 'slitheen';\n                case 4: return 'gallifreyan';\n                default: return 'extraterrestrial';\n            }\n        }\n    },\n    beforeSave: function(req, res) {\n        if(req.keys.get('type') == 'dalek' \u0026\u0026 req.keys.get('age') \u003e 200)\n            req.keys.set('type', 'supreme_dalek');\n            \n        res.success();\n    },\n    afterSave: function(req) {        \n        addToPapalMainframe(req.keys.get('id'));\n    }\n});\n```\n\nIn order to tell Warp Server to use the model we just created, we need to register it after we initialize Warp Server:\n\n```javascript\n// ... some code here\nvar api = new WarpServer(config);\napi.registerModel(Alien);\n// ... additional code to initialize here\n```\n\nNOTE: This approach is only advisable for development environments. For production environments, it is best to use the [Model Directory Approach](#using-model-directories).\n\nOnce completed, we can now use the Object API to operate on `alien` objects. See the section regarding the [Object API](rest.md#object-api) for more info.\n\n## Pointers\n\nRelations are a vital aspect of Relational Databases. With regards to the Warp Server, these are represented by `pointers`. Pointers are keys (fields) which point to specific objects from another table. This can be thought of as the `belongs_to` relationship or the `foreign_key` relationship in SQL databases. \n\nTo specify a `pointer` in your Model, you may do so by adding a `pointers` option in your `keys` config:\n\n```javascript\n{\n    keys: {\n        // Other key configurations...        \n        // Pointers configuration:\n        pointers: {\n            '{KEY_NAME}': {\n                className: '{CLASS_NAME_OF_POINTER}',\n                via: '{FOREIGN_KEY}' // OPTIONAL, if not set, the foreign key is assumed to be `className`_id\n            }\n        } \n    }\n}\n```\n\nSo if, for example, inside our `Alien` model, we would like to add pointers to a `Planet` model. We can do so by adding the following code to our `Model.create()` method:\n\n```javascript\n// Some code defining our model\nkeys: {\n    viewable: ['name', 'age', 'type', 'planet'],\n    actionable: ['name', 'age', 'type', 'planet'],\n    pointers: {\n        'planet': {\n            className: 'planet',\n            via: 'planet_id'\n        }\n    }\n},\n// Additional code defining our model\n```\n\nBy default, the pointer is joined using the `via` key of the class, and the `id` key of the pointer. However, there might be cases when the joins may not be as straightforward. For these scenarios, you can specify the `where` option.\nThe `where` option allows you to set special rules in order to connect to your pointer.\n\nFor example:\n\n```javascript\n// Some code defining our model\nkeys: {\n    viewable: ['name', 'age', 'type', 'planet'],\n    actionable: ['name', 'age', 'type', 'planet'],\n    pointers: {\n        'planet': {\n            className: 'planet',\n            via: 'planet_id',\n            where: {\n                'planet_id': {\n                    '_eq': 'planet.id'\n                },\n                'type': {\n                    '_eq': 'planet.race'\n                }\n            }\n        }\n    }\n},\n// Additional code defining our model\n```\n\nNote that the `where` option accepts a mapping of constraints.\n\nAvailable Constraints:\n\n- eq: equal to\n- neq: not equal to\n- gt: greater than\n- gte: greater than or equal to\n- lt: less than\n- lte: less than or equal to\n- ex: is not null/is null (value is either true or false)\n- in: contained in array\n- nin: not contained in array\n- str: starts with the specified string\n- end: ends with the specified string\n- has: contains the specified string (to search multiple keys, separate the key names with `|`)\n\nBy default, the value of each constraint is automatically filtered before it is added to the query. If you want to specify a raw field name as a value, you must append an underscore `_` before the constraint name.\n\nUnfiltered constraints:\n\n- _eq: equal to raw value\n- _neq: not equal to raw value\n- _gt: greater than raw value\n- _gte: greater than or equal to raw value\n- _lt: less than raw value\n- _lte: less than or equal to raw value\n\n## Files\n\nSometimes, you may need to upload files to your server and store them persistently. In this particular case, Warp Server helps simplify this process with the help of `Warp Files`. Warp Files allow you to define keys where you would want to store file-related content. \n\nOn the database side, it stores a `key` string which represents the file inside your desired file storage system. By default, Warp Server uses local storage, but you can define other forms of storage providers such as Amazon S3 or Azure Storage.\n\nTo specify a `file` in your Model, you may do so by adding a `files` option in your `keys` config:\n\n```javascript\n{\n    keys: {\n        // Other key configurations...        \n        // Files configuration:\n        files: ['{KEY_NAME}']\n    }\n}\n```\n\nSo if, for example, inside our `Alien` model, we would like to add a file named `profile_pic`. We can do so by adding the following code to our `Model.create()` method:\n\n```javascript\n// Some code defining our model\nkeys: {\n    viewable: ['name', 'age', 'type', 'planet', 'profile_pic'],\n    actionable: ['name', 'age', 'type', 'planet', 'profile_pic'],\n    pointers: {\n        'planet': {\n            className: 'planet',\n            via: 'planet_id'\n        }\n    },\n    files: ['profile_pic']\n},\n// Additional code defining our model\n```\n\n## User Authentication\n\nIn order to handle user authentication and management, a special type of model called the User model can be added. It is similar to the `WarpServer.Model` except it requires a few additional fields.\n\nFields required by the User Model:\n- username\n- password\n- email\n\nFor example, to create a User model using the `user` table:\n\n```javascript\nvar User = WarpServer.Model.create({\n    className: 'user',\n    keys: {\n        // NOTE: The password should not be viewable by the Object API\n        viewable: ['username', 'email'],\n        actionable: ['username', 'password', 'email']\n    },\n    validate: {\n        // Pre-defined validators are available for the fields required by the User Model\n        // See the section on Pre-defined Validators for more info.\n        'username': WarpServer.Model.Validation.FixedString(8, 16),\n        'password': WarpServer.Model.Validation.Password(8),\n        'email': WarpServer.Model.Validation.Email\n    },\n    parse: {\n        // Pre-defined Parsers\n        // See the section on Pre-defined Parsers for more info.\n        'username': WarpServer.Model.Parser.NoSpaces,\n        'password': WarpServer.Model.Parser.Password\n    }\n});\n```\n\nAside from the User Model, we should also define a Session Model that, like the User Model, has special required fields:\n\n- user (pointer)\n- origin\n- session_token\n- revoked_at\n\nAn example of a Session Model would be as follows:\n\n```javascript\nvar Session = WarpServer.Model.create({\n    className: 'session',\n    keys: {\n        // NOTE: The user field is a pointer to the 'user' table\n        // revoked_at is part of the table but is not viewable and actionable\n        viewable: ['user', 'origin', 'session_token'],\n        actionable: ['user', 'origin'],\n        pointers: {\n            'user': {\n                className: 'user',\n                via: 'user_id'\n            }\n        }\n    }\n    // NOTE: In order for us to generate special session tokens, we must use the Pre-defined PreSave function.\n    // For more info on these pre-defined functions, please see the secion on PreSave functions.\n    beforeSave: WarpServer.Model.PreSave.Session(30)\n});\n```\n\nThen, we register the created authentication models by adding it to our api:\n\n```javascript\n// ... some code here\nvar api = new WarpServer(config);\napi.registerAuthModels(User, Session);\n// ... additional code to initialize here\n```\n\nNOTE: To enable authentication, you must create both models.\nWe can now use the special user authentication and management operations made available by the [User API](rest.md#user-api).\n\n### Using Model Directories\n\n**NOTE: This is the recommended approach for production environments**\n\nIf you want to modularize your code into different files inside a folder, you can opt to place the folder name as a `source` option, instead of manually registering them to the api.\nAdditionally, you can also declare the `user` and `session` options using this approach. You just need to specify the filenames of the respective authentication models.\n\nFor example, if you have a directory structure such as the following:\n\n```\n|-- app\n|---- server\n|------ models\n|-------- alien.js\n|-------- planet.js\n|-------- user.js\n|-------- session.js\n|------ api.js\n|-- app.js\n```\n\nYou can declare your `api` inside `api.js`, and add a `models` option inside your configuration. For example:\n\n```javascript\n// References\nvar path = require('path');\nvar WarpServer = require('warp-server');\n\n// Export the api\nmodule.exports = new WarpServer({\n    security: {\n        apiKey: '12345678abcdefg',\n        masterKey: 'abcdefg12345678'\n    },\n    database: {\n        host: 'localhost',\n        port: 3306,\n        user: 'root',\n        password: 'password',\n        default: 'default_database',    \n    }\n    models: {\n        source: path.join(__dirname, 'models'),\n        user: 'user',\n        session: 'session'\n    }\n});\n```\n\nThen, reference the api inside `app.js`:\n\n```javascript\nvar express = require('express');\nvar api = require('./app/server/api');\nvar app = express();\n\napp.use('/api/1', api.router());\n```\n\n\n## Migrations\n\nManaging database schemas are usually handled by administrators using SQL clients. For Warp Server, we simplify this process by using `migrations`. Migrations make it easy to create, alter and drop database `schemas`. Additionally, they also allow versioning of these modifications, so you can easily `commit` or `revert` changes programmatically.\n\nTo activate the `migrations` feature, simply add a migrations option in your Warp Server config:\n\n```javascript\n// ... some config code here\nmodule.exports = new WarpServer({\n    // ... previous configs here\n    migrations: {\n        activated: true\n    }\n});\n```\n\nOnce applied and the server initiates, the migrations table is automatically created in the default database. By default, the name of the table is `migration`. If you need to change this, simply add a `className` option:\n\n```javascript\n// ... some config code here\nvar config = {\n    // ... previous configs here\n    migrations: {\n        activated: true,\n        className: 'migration_audit'\n    }\n};\nvar api = new WarpServer(config);\n// ... additional code to initialize here\n```\n\nYou can now access the `migrations` API to start creating `schemas`. Please see section on the [Migration API](rest.md#migration-api) for more info.\n\n\n## Functions\n\nOftentimes, there might be cases when the Object API may not be enough for your app requirements. In these cases, you may opt to use `Functions`.\n\n`Functions` allow you to set up custom API's to suit your app's growing needs.\n\nTo define a Function, simply create a `WarpServer.Function` class with the following parameters:\n\n```javascript\nWarpServer.Function.create({\n    // Unique name assigned to the endpoint, you can use Alphanumeric characters, underscores and/or dashes\n    name: '{FUNCTION_NAME}',\n    \n    // The action to run once the endpoint is called\n    action: function(request, response) {\n        // request.keys is a map that contains the modified keys of the object\n        // NOTE: Unlike the `.beforeSave()` function in Models, you can only use `.get()` for Functions\n        var key2 = request.keys.get('{KEY2}');\n        \n        // Check the client SDK performing the request (e.g. REST, Android, iOS,)\n        var client = request.client;\n\n        // Check the SDK version of the client request\n        var sdkVersion = request.sdkVersion;\n\n        // Check the version of the app that made the request\n        var appVersion = request.appVersion;\n                \n        // Call the success response after the keys have been manipulated\n        if(success)\n            response.success(/* The value you want to return to the user */);\n        else\n            // Or call the error response if an error has been encountered\n            response.error(error);\n    }\n});\n```\n\nFor example, if we want to make a function for destroying all aliens of a specific `type`, we can write it as:\n\n```javascript\n// Get a modified version of the Warp JS SDK from the API\n// For more info on the Warp JS SDK, please see http://github.com/dividedbyzeroco/warp-sdk-js\nvar api = new WarpServer(config);\nvar Warp = api.Warp;\n\n// Create the function\nvar destroyDaleks = WarpServer.Function.create({\n    name: 'destroy-aliens',\n    action: function(req, res) {\n        var type = req.keys.get('type');\n        var query = new Warp.Query('alien');\n        \n        query.equalTo('type', type)\n        .find(function(aliens) {\n            // Destroy aliens asynchronously\n            aliens.each(function(alien) {\n                return alien.destroy();\n            });\n            \n            // Return a response\n            res.success('Deleted all `' + type + '` aliens');\n        })\n        .catch(function(error) {\n            res.error(error);\n        });\n    }\n});\n```\n\nIn order to use the function we just created, we should register it after we initialize Warp Server:\n\n```javascript\n// ... some code here\napi.registerFunction(destroyDaleks);\n// ... additional code to initialize here\n```\n\nYou can also opt to specify a folder where all your functions are stored. Just like in the section regarding the [Model Directory Approach](#using-model-directories).\n\nFor example, if we have a directory such as this:\n\n```\n|-- app\n|---- server\n|------ models\n|------ functions\n|-------- destroy-daleks.js\n|------ api.js\n|-- app.js\n```\n\nYou can add the functions inside `api.js`:\n\n```javascript\n// ... some code here\nmodule.exports = new WarpServer({\n    // .. previous configs here\n    functions: {\n        source: path.join(__dirname, 'functions')\n    }\n});\n```\n\nThe Functions are now ready to be called. For more info, see the section regarding the [Function API](rest.md#function-api).\n\n\n## Queues\n\nFunctions are useful for running adhoc tasks; however, if you want to run frequent background jobs, you can use `Queues`. `Queues` are specific tasks which are executed periodically based on a given interval. The Warp Server allows you to easily start, stop and get statuses for these different background jobs.\n\nTo define a Queue, simply create a `WarpServer.Queue` class with the following parameters:\n\n```javascript\nWarpServer.Queue.create({\n    // Unique name assigned to the endpoint, you can use Alphanumeric characters, underscores and/or dashes\n    name: '{FUNCTION_NAME}',\n    \n    // The action to run for every interval\n    action: function() {\n        // Perform any task here\n    },\n    \n    // A pre-defined interval that determines the frequency of a given task\n    // The interval follows the format of the Cron Job in Linux\n    // For more information about interval formats, please see http://npmjs.com/package/cron\n    interval: '{INTERVAL}',\n    \n    // An OPTIONAL parameter that determines the relative timezone that the interval would follow\n    // The default value is UTC\n    timezone: '{TIMEZONE}'\n});\n```\n\nFor example, if we want to make a queue for sending messages, we can write it as:\n\n```javascript\n// Get a modified version of the Warp JS SDK from the API\n// For more info on the Warp JS SDK, please see http://github.com/dividedbyzeroco/warp-sdk-js\nvar api = new WarpServer(config);\nvar Warp = api.Warp;\n\n// Create the queue\nvar sendMessages = WarpServer.Queue.create({\n    name: 'send-messages',\n    action: function() {\n        var query = new Warp.Query('message');\n        \n        query.doesNotExist('sent_at')\n        .find(function(messages) {\n            // Sending messages asynchronously\n            messages.each(function(message) {\n                console.log(message.get('content'));\n            });\n        })\n        .catch(function(error) {\n            res.error(error);\n        });\n    },\n    interval: '* * 10 * * *' // Run every 10 o'clock\n});\n```\n\nIn order to use the queue we just created, we should register it after we initialize Warp Server:\n\n```javascript\n// ... some code here\napi.registerQueue(sendMessages);\n// ... additional code to initialize here\n```\n\nYou can also opt to specify a folder where all your queues are stored. Just like in the section regarding the [Model Directory Approach](#using-model-directories).\n\nFor example, if we have a directory such as this:\n\n```\n|-- app\n|---- server\n|------ models\n|------ functions\n|------ queues\n|-------- send-messages.js\n|------ api.js\n|-- app.js\n```\n\nYou can add the queues inside `api.js`:\n\n```javascript\n// ... some code here\nmodule.exports = new WarpServer({\n    // .. previous configs here\n    queues: {\n        source: path.join(__dirname, 'queues')\n    }\n});\n```\n\nThe Queues are now ready to be used. For more info, see the section regarding the [Queue API](rest.md#queue-api).\n\n\n### Third-party Libraries\n\n- [async](http://npmjs.com/package/async)\n- [bcryptjs](http://npmjs.com/package/bcryptjs)\n- [body-parser](http://npmjs.com/package/body-parser)\n- [cron](http://npmjs.com/package/cron)\n- [express](http://npmjs.com/package/express)\n- [moment-timezone](http://npmjs.com/package/moment-timezone)\n- [multer](http://npmjs.com/package/multer)\n- [mysql](http://npmjs.com/package/mysql)\n- [promise](http://npmjs.com/package/promise)\n- [underscore](http://npmjs.com/package/underscore)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdividedbyzeroco%2Fwarp-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdividedbyzeroco%2Fwarp-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdividedbyzeroco%2Fwarp-server/lists"}