{"id":25853765,"url":"https://github.com/bhrott/shura-js","last_synced_at":"2025-03-01T15:19:50.746Z","repository":{"id":57359058,"uuid":"108044162","full_name":"bhrott/shura-js","owner":"bhrott","description":"A simple and extensible json schema extractor for NodeJS","archived":false,"fork":false,"pushed_at":"2017-11-08T20:25:12.000Z","size":213,"stargazers_count":5,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-16T11:33:54.826Z","etag":null,"topics":["extract","json","nodejs","schema","validation"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bhrott.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-23T21:50:49.000Z","updated_at":"2017-11-05T18:43:10.000Z","dependencies_parsed_at":"2022-09-06T21:41:31.885Z","dependency_job_id":null,"html_url":"https://github.com/bhrott/shura-js","commit_stats":null,"previous_names":["benhurott/shura-js"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhrott%2Fshura-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhrott%2Fshura-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhrott%2Fshura-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhrott%2Fshura-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bhrott","download_url":"https://codeload.github.com/bhrott/shura-js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241382094,"owners_count":19953830,"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":["extract","json","nodejs","schema","validation"],"created_at":"2025-03-01T15:19:50.166Z","updated_at":"2025-03-01T15:19:50.728Z","avatar_url":"https://github.com/bhrott.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![shurajs](resources/shura-js-logo.png)\n\n\n# shura-js\nA simple and extensible json schema extractor for NodeJS.\n\n![build status](https://travis-ci.org/benhurott/shura-js.svg?branch=master)\n\n## Motivation\nWhen we use a NoSql database such MongoDB or Firebase, we need to prevent user to input some invalid additional data to our database. This lib will help you to preserve the schema of your data.\n\nEx: \u003cbr /\u003e\nYour schema for user data is:\n```json\n{\n    \"name\": \"Ben-hur Santos Ott\",\n    \"email\": \"ben-hur@email.com\",\n    \"role\": \"Developer\"\n}\n```\n\nYou api normaly validate if the `name` is a valid string, the `email` is a valid e-mail address and `role` is one of listed items.\n\nOk, if all of this is valid, pass the data to databse.\n\nBuuuut, if a matrix hacker attacks your api directly sending:\n```json\n{\n    \"name\": \"Ben-hur Santos Ott\",\n    \"email\": \"ben-hur@email.com\",\n    \"role\": \"Developer\",\n\n    \"_hack_\": \"\u003csome giant string like img base64\u003e\"\n}\n```\n\nDo you validate if user is sending additional invalid data?\n\nIf your answer is `YES`, congratulations. Otherwise, you have a great issue in your application.\n\n## Using ShuraJS\n\nInstall it:\n```\nnpm install --save shurajs\n```\n\nUsing the previous example\n\nFirst: create a schema for your object.\n\n```js\nconst shurajs = require('shurajs')\n\nconst schema = {\n    \"name\": {\n        \"*\": \"string\"\n    },\n    \"email\": {\n        \"*\": \"string\"\n    },\n    \"role\": {\n        \"*\": \"string\"\n    }\n}\n```\n\nSecond: extract valid object.\n\n```js\n//...\nconst dataToBeSaved = {\n    \"name\": \"Ben-hur Santos Ott\",\n    \"email\": \"ben-hur@email.com\",\n    \"role\": \"Developer\",\n\n    \"_hack_\": \"\u003csome giant string like img base64\u003e\"\n}\n\nconst sanitized = shurajs.extract(dataToBeSaved, schema)\nconsole.log(sanitized)\n```\n\nConsole will log this:\n```json\n{\n    \"name\": \"Ben-hur Santos Ott\",\n    \"email\": \"ben-hur@email.com\",\n    \"role\": \"Developer\"\n}\n```\n\n## API\nIn previous sample, you saw:\n```js\n{\n    \"name\": {\n        \"*\": \"string\"\n    }\n    //...\n}\n```\n\nThis is the extractor template shurajs uses to validate, parse and extract using this rule:\n* the property `name` is not `null`, not `undefined` and is a `string`?\n    * `false`: don't include this node on result.\n    * `true`: include in result\n\nNow, let's see available apis:\n\n*Notes*: `Error Codes` is used in `onValidationFailed` on `Global` section.\n\n### String\nValidate if value is a string\n```js\n{\n    \"*\": \"string\",\n\n    // valid if string length has min 10 characters\n    // (optional, int, default null)\n    \"minLength\": 10, \n\n    // valid if string length has no more than 50 characters\n    // (optional, int, default null)\n    \"maxLength\": 50,\n\n    // validate if regex matches the value\n    // (optional, regex, default null)\n    \"regex\": /[0-9]/,\n\n    // consideting valid if string has length 0 or contains only white spaces.\n    // (optional, boolean, default true)\n    \"allowEmpty\": true\n}\n```\n\nError Codes:\n```\nnot_a_string -\u003e the value is not a string\nmin_length -\u003e the value has less characters than expected\nmax_length -\u003e the value has more characters than expected\nregex -\u003e the regex not matched\nis_empty -\u003e raises when allowEmpty=true validation failed\n```\n\n### Number\nValidate if value is a number\n```js\n{\n    \"*\": \"number\",\n\n    // validate if value is greather or equal then 2\n    // (optional, int, default null)\n    \"min\": 2,\n\n    // validate if value is less or equal then 100\n    // (optional, int, default null)\n    \"max\": 100,\n\n    // validate if value is negative\n    // (optional, boolean, default true)\n    \"allowNegative\": true,\n\n    // validate if value is positive (zero is positive for us)\n    // (optional, boolean, default true)\n    \"allowPositive\": true,\n}\n```\n\nError Codes:\n```\nnot_a_number -\u003e the value is not a number\nmin -\u003e the value is minor then the expected\nmax -\u003e the value is major then the expected\nis_negative -\u003e the value is negative for allowNegative=false\nis_positive -\u003e the value is positive for allowPositive=false\n```\n\n### Boolean\nValidate if value is a boolean\n```js\n{\n    \"*\": \"boolean\"\n}\n```\n\nError Codes:\n```\nnot_a_boolean -\u003e the value is not a boolean\n```\n\n### Object\nValidate object structure\n```js\n{\n    \"*\": \"object\",\n\n    // definition is the structure of your model.\n    \"definition\": {\n        \"myNameProperty\": {\n            \"*\": \"string\"\n        },\n        \"myAgeProperty\": {\n            \"*\": \"number\",\n            \"min\": 5,\n            \"max\": 100\n        }\n    }\n}\n```\n\nSample:\n```js\nconst shurajs = require('shurajs')\n\nconst model = {\n    \"name\": \"Ben-hur Santos Ott\",\n    \"contacts\": {\n        \"email\": \"ben-hur@email.com\",\n        \"phone\": \"+55 51 99999-9999\"\n    }\n}\n\nconst schema = {\n    \"name\": { \n        \"*\": \"string\",\n        \"minLength\": 5,\n        \"maxLength\": 100\n    },\n    \"contacts\": {\n        \"*\": \"object\",\n        \"definition\": {\n            \"email\": { \n                \"*\": \"string\",\n                \"regex\": /^(([^\u003c\u003e()\\[\\]\\\\.,;:\\s@\"]+(\\.[^\u003c\u003e()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/\n            },\n            \"phone\": {\n                \"*\": \"string\",\n                \"required\": false\n            }\n        }\n    }\n}\n\nconst sanitized = shurajs.extract(model, schema)\n```\n\nError Codes:\n```\nnot_a_object -\u003e value is not null, not undefined and not an object\n```\n\n### Array\nValidate if value is an array. If you want, you can check types of elements inside the array.\n\n```js\n{\n    \"*\": \"array\",\n    \n    // validate if array has one or more elements\n    // (optional, int, default null)\n    \"minLength\": 1,\n\n    // validate if array has no more than 30 elements\n    // (optional, int, default null)\n    \"maxLength\": 30,\n\n    // validate if values inside the array matches a schema.\n    // you can pass more then one schema, if you do this, if the\n    // first schema fails, try the second and so on.\n    // if one of the schemas pass the validation, the data will be included on result.\n    // the invalid items will be removed from array\n    // (optional, array, default [])\n    \"innerTypes\": [\n        {\n            \"*\": \"object\",\n            // same as type: object...\n        },\n        {\n            \"*\": \"string\",\n            // ....\n        }\n    ],\n\n    // when validation fails in extractor, the property will be deleted.\n    // in some cases, you want to preserve property and has some default\n    // value (like empty array). \n    // use this prop for it.\n    // (optional, any, default undefined)\n    \"resolveInvalidAs\": undefined\n}\n```\n\nError Codes:\n```\nnot_a_array -\u003e value is not an array\nmin_length -\u003e array has less items then expected\nmax_length -\u003e array has more items then expected\ninner_type_validation_failed -\u003e some value not match with inner type\n```\n\n### oneOf\nValidate if value is one of listed values (using `===` for comparison)\n```js\n{\n    \"*\": \"oneOf\",\n\n    // list of items to compare with value\n    \"items\": [10, \"test\", null]\n}\n```\n\nError Codes:\n```\ninvalid_item -\u003e the value is not in the items range.\n```\n\n### Global\nAll templates include these properties if you want to use:\n\n```js\n{\n    \"*\": \"\u003cany type\u003e\",\n    \n    // if set to true and property value is null or undefined\n    // it will force `onValidationFailed` to be trigged\n    // (optional, boolean, default false)\n    \"required\": false,\n\n    // by default, shurajs ignore the node if value is undefined.\n    // if you want a default value for invalid node, just set this\n    // property with your custom value\n    // (optional, any type, default undefined)\n    \"defaultValue\": undefined,\n\n    // when some schema validation failed, this method will be called.\n    // use it for custom error behavior (like raise an exception for example.)\n    \"onValidationFailed\": (schema, originalValue, errorCode) =\u003e {\n        //...\n    }\n\n    // after shurajs parses the value and apply all the rules,\n    // it will resolve the value and set it on the result node.\n    // if you want to validate value manualy after shura (in case\n    // you have some complex validation, for example) you can use\n    // this method.\n    // the value you returned on `afterValidation` will be the result\n    // of the node.\n    // (optional, schema:value func, default return current value)\n    \"afterValidation\": (schema, currentValue) =\u003e {\n        //...\n        return currentValue\n    }\n}\n```\n\n\n## Extending ShuraJS\nIf you want to create your custom extractors, just use the `mixin` function.\n\nSo, if want to create a default `age validation schema` that validate number \u003c 18 or \u003e 99:\n```js\nconst shurajs = require('shurajs')\n\nconst schema = {\n    age: {\n        '*': 'age'\n    }\n}\n\nconst model = {\n    age: 42\n}\n\nconst sanitized = shurajs.extract(schema, model)\n```\n\nYou will create some like this:\n```js\nconst shurajs = require('shurajs')\n\nshurajs.mixin('age', (schema, value) =\u003e {\n    // in this case, the schema will have this obj:\n    // {\n    //     '*': 'age'\n    // }\n\n    // the value has: 42\n\n    if (value \u003c 18 || value \u003e 99) {\n        // by default, if you return `undefined`,\n        // shurajs will consider it a invalid result\n        // and will not include in the object node.\n        return undefined\n    }\n\n    // after all validations, return a value that be include\n    // in the result node\n    return value\n})\n\n```\n\n\n## Thanks to\nIcon: \u003cdiv\u003eIcons made by \u003ca href=\"http://www.freepik.com\" title=\"Freepik\"\u003eFreepik\u003c/a\u003e from \u003ca href=\"https://www.flaticon.com/\" title=\"Flaticon\"\u003ewww.flaticon.com\u003c/a\u003e is licensed by \u003ca href=\"http://creativecommons.org/licenses/by/3.0/\" title=\"Creative Commons BY 3.0\" target=\"_blank\"\u003eCC 3.0 BY\u003c/a\u003e\u003c/div\u003e\n\n\n## Changelog\n\n### 0.12.1\n* Fixing `defaultValue` on `object` api.\n\n### 0.12.0\n* Refactoring `middleware` to `afterValidation`\n\n**Breaking Change**\u003cbr /\u003e\n`middleware` no longer works, use `afterValidation` instead.\n\n### 0.11.0\n* Adding `onValidationFailed` to schemas.\n\n**Breaking Change**\u003cbr /\u003e\n`required` now trigger `onValidationFailed` instead raising error.\n\n### 0.10.0\n* Adding `middleware`.\n\n### 0.9.0\n* Adding `defaultValue`.\n\n### 0.8.0\n* Adding `mixins`.\n\n### 0.7.1\n* First version =D\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhrott%2Fshura-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbhrott%2Fshura-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhrott%2Fshura-js/lists"}