{"id":13524237,"url":"https://github.com/fastify/fluent-json-schema","last_synced_at":"2025-04-11T03:29:40.655Z","repository":{"id":38081106,"uuid":"153112895","full_name":"fastify/fluent-json-schema","owner":"fastify","description":"A fluent API to generate JSON schemas","archived":false,"fork":false,"pushed_at":"2025-04-02T14:00:34.000Z","size":608,"stargazers_count":506,"open_issues_count":10,"forks_count":57,"subscribers_count":19,"default_branch":"main","last_synced_at":"2025-04-03T19:51:23.903Z","etag":null,"topics":["fastify-library"],"latest_commit_sha":null,"homepage":"https://npmjs.com/package/fluent-json-schema","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/fastify.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"fastify","open_collective":"fastify"}},"created_at":"2018-10-15T12:55:57.000Z","updated_at":"2025-04-02T14:00:33.000Z","dependencies_parsed_at":"2023-10-01T21:53:39.782Z","dependency_job_id":"23f6f792-5c6a-4e12-86e7-5e39a5758e81","html_url":"https://github.com/fastify/fluent-json-schema","commit_stats":{"total_commits":327,"total_committers":37,"mean_commits":8.837837837837839,"dds":0.4740061162079511,"last_synced_commit":"a7c7366d237789f9f0ef09d09594daf761dd0acf"},"previous_names":["fastify/fluent-schema"],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Ffluent-json-schema","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Ffluent-json-schema/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Ffluent-json-schema/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Ffluent-json-schema/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fastify","download_url":"https://codeload.github.com/fastify/fluent-json-schema/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248335246,"owners_count":21086542,"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":["fastify-library"],"created_at":"2024-08-01T06:01:08.262Z","updated_at":"2025-04-11T03:29:40.646Z","avatar_url":"https://github.com/fastify.png","language":"JavaScript","readme":"# fluent-json-schema\n\nA fluent API to generate JSON schemas (draft-07) for Node.js and browser. Framework agnostic.\n\n[![view on npm](https://img.shields.io/npm/v/fluent-json-schema.svg)](https://www.npmjs.org/package/fluent-json-schema)\n[![CI](https://github.com/fastify/fluent-json-schema/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/fluent-json-schema/actions/workflows/ci.yml)\n[![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard)\n\n## Features\n\n- Fluent schema implements JSON Schema draft-07 standards\n- Faster and shorter way to write a JSON Schema via a [fluent API](https://en.wikipedia.org/wiki/Fluent_interface)\n- Runtime errors for invalid options or keywords misuse\n- JavaScript constants can be used in the JSON schema (e.g. _enum_, _const_, _default_ ) avoiding discrepancies between model and schema\n- TypeScript definitions\n- Coverage 100%\n\n## Install\n\n    npm i fluent-json-schema\n\nor\n\n    yarn add fluent-json-schema\n\n## Usage\n\n```javascript\nconst S = require('fluent-json-schema')\n\nconst ROLES = {\n  ADMIN: 'ADMIN',\n  USER: 'USER',\n}\n\nconst schema = S.object()\n  .id('http://foo/user')\n  .title('My First Fluent JSON Schema')\n  .description('A simple user')\n  .prop('email', S.string().format(S.FORMATS.EMAIL).required())\n  .prop('password', S.string().minLength(8).required())\n  .prop('role', S.string().enum(Object.values(ROLES)).default(ROLES.USER))\n  .prop(\n    'birthday',\n    S.raw({ type: 'string', format: 'date', formatMaximum: '2020-01-01' }) // formatMaximum is an AJV custom keywords\n  )\n  .definition(\n    'address',\n    S.object()\n      .id('#address')\n      .prop('line1', S.anyOf([S.string(), S.null()])) // JSON Schema nullable\n      .prop('line2', S.string().raw({ nullable: true })) // Open API / Swagger  nullable\n      .prop('country', S.string())\n      .prop('city', S.string())\n      .prop('zipcode', S.string())\n      .required(['line1', 'country', 'city', 'zipcode'])\n  )\n  .prop('address', S.ref('#address'))\n\nconsole.log(JSON.stringify(schema.valueOf(), undefined, 2))\n```\n\nSchema generated:\n\n```json\n{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"definitions\": {\n    \"address\": {\n      \"type\": \"object\",\n      \"$id\": \"#address\",\n      \"properties\": {\n        \"line1\": {\n          \"anyOf\": [\n            {\n              \"type\": \"string\"\n            },\n            {\n              \"type\": \"null\"\n            }\n          ]\n        },\n        \"line2\": {\n          \"type\": \"string\",\n          \"nullable\": true\n        },\n        \"country\": {\n          \"type\": \"string\"\n        },\n        \"city\": {\n          \"type\": \"string\"\n        },\n        \"zipcode\": {\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\"line1\", \"country\", \"city\", \"zipcode\"]\n    }\n  },\n  \"type\": \"object\",\n  \"$id\": \"http://foo/user\",\n  \"title\": \"My First Fluent JSON Schema\",\n  \"description\": \"A simple user\",\n  \"properties\": {\n    \"email\": {\n      \"type\": \"string\",\n      \"format\": \"email\"\n    },\n    \"password\": {\n      \"type\": \"string\",\n      \"minLength\": 8\n    },\n    \"birthday\": {\n      \"type\": \"string\",\n      \"format\": \"date\",\n      \"formatMaximum\": \"2020-01-01\"\n    },\n    \"role\": {\n      \"type\": \"string\",\n      \"enum\": [\"ADMIN\", \"USER\"],\n      \"default\": \"USER\"\n    },\n    \"address\": {\n      \"$ref\": \"#address\"\n    }\n  },\n  \"required\": [\"email\", \"password\"]\n}\n```\n\n## TypeScript\n\n### CommonJS\n\nWith `\"esModuleInterop\": true` activated in the `tsconfig.json`:\n\n```typescript\nimport S from 'fluent-json-schema'\n\nconst schema = S.object()\n  .prop('foo', S.string())\n  .prop('bar', S.number())\n  .valueOf()\n```\n\nWith `\"esModuleInterop\": false` in the `tsconfig.json`:\n\n```typescript\nimport * as S from 'fluent-json-schema'\n\nconst schema = S.object()\n  .prop('foo', S.string())\n  .prop('bar', S.number())\n  .valueOf()\n```\n\n### ESM\n\nA named export is also available to work with native ESM modules:\n\n```typescript\nimport { S } from 'fluent-json-schema'\n\nconst schema = S.object()\n  .prop('foo', S.string())\n  .prop('bar', S.number())\n  .valueOf()\n```\n\n## Validation\n\nFluent schema **does not** validate a JSON schema. However, many libraries can do that for you.\nBelow are a few examples using [AJV](https://ajv.js.org/):\n\n    npm i ajv\n\nor\n\n    yarn add ajv\n\n### Validate an empty model\n\nSnippet:\n\n```javascript\nconst ajv = new Ajv({ allErrors: true })\nconst validate = ajv.compile(schema.valueOf())\nlet user = {}\nlet valid = validate(user)\nconsole.log({ valid }) //=\u003e {valid: false}\nconsole.log(validate.errors) //=\u003e {valid: false}\n```\n\nOutput:\n\n```\n{valid: false}\nerrors: [\n  {\n    keyword: 'required',\n    dataPath: '',\n    schemaPath: '#/required',\n    params: { missingProperty: 'email' },\n    message: \"should have required property 'email'\",\n  },\n  {\n    keyword: 'required',\n    dataPath: '',\n    schemaPath: '#/required',\n    params: { missingProperty: 'password' },\n    message: \"should have required property 'password'\",\n  },\n]\n\n```\n\n### Validate a partially filled model\n\nSnippet:\n\n```javascript\nuser = { email: 'test', password: 'password' }\nvalid = validate(user)\nconsole.log({ valid })\nconsole.log(validate.errors)\n```\n\nOutput:\n\n```\n{valid: false}\nerrors:\n[ { keyword: 'format',\n    dataPath: '.email',\n    schemaPath: '#/properties/email/format',\n    params: { format: 'email' },\n    message: 'should match format \"email\"' } ]\n\n```\n\n### Validate a model with a wrong format attribute\n\nSnippet:\n\n```javascript\nuser = { email: 'test@foo.com', password: 'password' }\nvalid = validate(user)\nconsole.log({ valid })\nconsole.log('errors:', validate.errors)\n```\n\nOutput:\n\n```\n{valid: false}\nerrors: [ { keyword: 'required',\n    dataPath: '.address',\n    schemaPath: '#definitions/address/required',\n    params: { missingProperty: 'country' },\n    message: 'should have required property \\'country\\'' },\n  { keyword: 'required',\n    dataPath: '.address',\n    schemaPath: '#definitions/address/required',\n    params: { missingProperty: 'city' },\n    message: 'should have required property \\'city\\'' },\n  { keyword: 'required',\n    dataPath: '.address',\n    schemaPath: '#definitions/address/required',\n    params: { missingProperty: 'zipcoce' },\n    message: 'should have required property \\'zipcode\\'' } ]\n```\n\n### Valid model\n\nSnippet:\n\n```javascript\nuser = { email: 'test@foo.com', password: 'password' }\nvalid = validate(user)\nconsole.log({ valid })\n```\n\nOutput:\n\n    {valid: true}\n\n## Extend schema\n\nNormally inheritance with JSON Schema is achieved with `allOf`. However, when `.additionalProperties(false)` is used the validator won't\nunderstand which properties come from the base schema. `S.extend` creates a schema merging the base into the new one so\nthat the validator knows all the properties because it evaluates only a single schema.\nFor example, in a CRUD API `POST /users` could use the `userBaseSchema` rather than `GET /users` or `PATCH /users` use the `userSchema`\nwhich contains the `id`, `createdAt`, and `updatedAt` generated server side.\n\n```js\nconst S = require('fluent-json-schema')\nconst userBaseSchema = S.object()\n  .additionalProperties(false)\n  .prop('username', S.string())\n  .prop('password', S.string())\n\nconst userSchema = S.object()\n  .prop('id', S.string().format('uuid'))\n  .prop('createdAt', S.string().format('time'))\n  .prop('updatedAt', S.string().format('time'))\n  .extend(userBaseSchema)\n\nconsole.log(userSchema)\n```\n\n## Selecting certain properties of your schema\n\nIn addition to extending schemas, it is also possible to reduce them into smaller schemas. This comes in handy\nwhen you have a large Fluent Schema, and would like to re-use some of its properties.\n\nSelect only properties you want to keep.\n\n```js\nconst S = require('fluent-json-schema')\nconst userSchema = S.object()\n  .prop('username', S.string())\n  .prop('password', S.string())\n  .prop('id', S.string().format('uuid'))\n  .prop('createdAt', S.string().format('time'))\n  .prop('updatedAt', S.string().format('time'))\n\nconst loginSchema = userSchema.only(['username', 'password'])\n```\n\nOr remove properties you dont want to keep.\n\n```js\nconst S = require('fluent-json-schema')\nconst personSchema = S.object()\n  .prop('name', S.string())\n  .prop('age', S.number())\n  .prop('id', S.string().format('uuid'))\n  .prop('createdAt', S.string().format('time'))\n  .prop('updatedAt', S.string().format('time'))\n\nconst bodySchema = personSchema.without(['createdAt', 'updatedAt'])\n```\n\n### Detect Fluent Schema objects\n\nEvery Fluent Schema object contains a boolean `isFluentSchema`. In this way, you can write your own utilities that understand the Fluent Schema API and improve the user experience of your tool.\n\n```js\nconst S = require('fluent-json-schema')\nconst schema = S.object().prop('foo', S.string()).prop('bar', S.number())\nconsole.log(schema.isFluentSchema) // true\n```\n\n## Documentation\n\n- [Full API Documentation](./docs/API.md).\n- [JSON schema draft-07 reference](https://json-schema.org/draft-07/draft-handrews-json-schema-01).\n\n## Acknowledgments\n\nThanks to [Matteo Collina](https://twitter.com/matteocollina) for pushing me to implement this utility! 🙏\n\n## Related projects\n\n- JSON Schema [Draft 7](http://json-schema.org/specification-links.html#draft-7)\n- [Understanding JSON Schema](https://json-schema.org/understanding-json-schema/) (despite referring to draft 6 the guide is still good for grasping the main concepts)\n- [AJV](https://ajv.js.org/) JSON Schema validator\n- [jsonschema.net](https://www.jsonschema.net/) an online JSON Schema visual editor (it does not support advanced features)\n\n## License\n\nLicensed under [MIT](./LICENSE).\n","funding_links":["https://github.com/sponsors/fastify","https://opencollective.com/fastify"],"categories":["JavaScript","others"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastify%2Ffluent-json-schema","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffastify%2Ffluent-json-schema","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastify%2Ffluent-json-schema/lists"}