{"id":24807166,"url":"https://github.com/eddienubes/validness","last_synced_at":"2025-06-28T04:36:15.886Z","repository":{"id":40304700,"uuid":"440780732","full_name":"eddienubes/validness","owner":"eddienubes","description":"🟢 Your favourite library for validating incoming data in express.js.","archived":false,"fork":false,"pushed_at":"2025-04-28T15:50:58.000Z","size":9731,"stargazers_count":10,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-09T17:52:35.445Z","etag":null,"topics":["data","dto","express","expressjs","http","http-server","nestjs","nodejs","server","validation"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/eddienubes.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,"zenodo":null}},"created_at":"2021-12-22T08:04:04.000Z","updated_at":"2025-01-30T07:48:48.000Z","dependencies_parsed_at":"2023-01-30T03:45:51.427Z","dependency_job_id":"20339cb1-4efe-4bd5-a71c-c033566e0eb6","html_url":"https://github.com/eddienubes/validness","commit_stats":{"total_commits":143,"total_committers":4,"mean_commits":35.75,"dds":0.3356643356643356,"last_synced_commit":"eb42482a7f6b7e8890c392851d33541700c709a5"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/eddienubes/validness","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eddienubes%2Fvalidness","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eddienubes%2Fvalidness/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eddienubes%2Fvalidness/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eddienubes%2Fvalidness/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eddienubes","download_url":"https://codeload.github.com/eddienubes/validness/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eddienubes%2Fvalidness/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262376235,"owners_count":23301344,"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":["data","dto","express","expressjs","http","http-server","nestjs","nodejs","server","validation"],"created_at":"2025-01-30T09:17:22.768Z","updated_at":"2025-06-28T04:36:15.861Z","avatar_url":"https://github.com/eddienubes.png","language":"TypeScript","readme":"# Validness 💦\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/eddienubes/validness/blob/master/misc/water.png?raw=true\" alt=\"water\" width=\"30\"\u003e\n    \u003cimg src=\"https://github.com/eddienubes/validness/blob/master/misc/water2.png?raw=true\" alt=\"water2\" width=\"30\"\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/eddienubes/validness/actions/workflows/ci.yml/badge.svg\" alt=\"ci-status\" /\u003e\n    \u003ca href=\"https://www.npmjs.com/package/sagetest\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/validness?color=729B1B\u0026label=npm\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://www.npmjs.com/package/sagetest\"\u003e\u003cimg src=\"https://img.shields.io/npm/dw/validness\" alt=\"npm version\" height=\"18\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://codecov.io/gh/eddienubes/validness\" \u003e \n        \u003cimg src=\"https://codecov.io/gh/eddienubes/validness/graph/badge.svg?token=3FU7I90B4Q\"/\u003e \n    \u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n🟢 Your favourite library for validating incoming data in [express.js](https://expressjs.com/).\n\nWith the creation of a single class and usage of decorators, we achieve validation of the following content types (body\nparser required):\n\n- application/json\n- multipart/form-data (yes, with files and text fields)\n\n\u003e Also, this library supports both ESM and CJS versions via dynamic exports in package.json.\n---\n\n## ⚙️ Installation:\n\n1. It has some important peer dependencies:\n\n- class-validator\n- class-transformer\n- reflect-metadata\n\n  _Optional, for multipart/form-data parsing only (These are truly optional):_\n- multer _(recommended)_\n- formidable (yes, we support an ESM version only)\n\n```shell\nyarn add validness class-validator class-transformer reflect-metadata\nnpm install validness class-validator class-transformer reflect-metadata\n```\n\nPlease import reflect-metadata in an entry file of your project in order for this package to work\n\n```typescript\nimport 'reflect-metadata'\n// your code\n```\n\nFor typescript decorators usage turn this option on in your **tsconfig.json** file.\n\n```json\n{\n  \"compilerOptions\": {\n    \"experimentalDecorators\": true\n  }\n}\n```\n\n---\n\n## ✍ Usage:\n\n### Body validation\n\nAs stated above, we're going to use decorators.\nLet's create a DTO of commonly expected data:\n\n_registration.dto.ts_\n\n```typescript\nimport { IsEmail, IsPhoneNumber } from \"class-validator\";\n\nexport class RegistrationDto {\n  @IsPhoneNumber()\n  phone: ValidatedFile;\n\n  @IsEmail()\n  email: string;\n}\n```\n\n_registration.controller.ts_\n\n```typescript\nimport { Router } from \"express\";\nimport { validationBodyPipe, DefaultBodyError } from \"validness\";\nimport { RegistrationDto } from './registration.dto.ts';\nimport { StatusCodes } from \"http-status-codes\";\n\nconst router = Router()\n\n// controller\nrouter.post('/', validationBodyPipe(RegistrationDto), async (req, res, next) =\u003e {\n  const validatedBody = req.body as RegistrationDto;\n\n  await registerUser(validatedBody);\n\n  res.json({ message: 'SUCCESS' })\n});\n\n// Error handling\nrouter.use((err, req, res, next) =\u003e {\n  // validness throws Default error models if customErrorFactory isn't sepcified.\n  // Standard models contain everything you need, like status code and errored fields\n  if (err instanceof DefaultBodyError) {\n    // implement handling logic\n    res.status(StatusCodes.BAD_REQUEST).json({ message: 'ERROR' });\n  }\n});\n```\n\n### Query validation\n\nLet's create a query DTO with a use of decorators.\nAs you might know, query params always contain strings, you can transform them\nwith [class-transformer](https://github.com/typestack/class-transformer) decorators.\n\n_get-users-query.dto.ts_\n\n```typescript\nimport { IsEmail, IsNotEmpty, IsNumberString, IsPhoneNumber } from \"class-validator\";\n\nexport class GetUsersQueryDto {\n  @IsString()\n  @IsNotEmpty()\n  query: string;\n\n  @IsNumberString()\n  pageIndex: string;\n\n  @IsNumberString()\n  perPage: string;\n}\n```\n\n_users.controller.ts_\n\n```typescript\nimport { Router } from \"express\";\nimport { GetUsersQueryDto } from './get-users-query.dto.ts';\nimport { validationQueryPipe, DefaultQueryError } from \"validness\";\nimport { StatusCodes } from \"http-status-codes\";\n\nconst router = Router()\n\n// controller\nrouter.get('/', validationQueryPipe(GetUsersQueryDto), async (req, res, next) =\u003e {\n  const validatedQuery = req.query as GetUsersQueryDto;\n\n  await findUsers(validatedQuery);\n\n  res.json({ message: 'SUCCESS' })\n});\n\n// Error handling\nrouter.use((err, req, res, next) =\u003e {\n  // validness throws Default error models if customErrorFactory isn't sepcified.\n  // Standard models contain everything you need, like status code and errored fields\n  if (err instanceof DefaultQueryError) {\n    // implement handling logic\n    res.status(StatusCodes.BAD_REQUEST).json({ message: 'ERROR' });\n  }\n});\n```\n\n### Multipart Form Data validation\n\nInstall an underlying driver of your choice:\n\n- multer (highly recommended)\n- formidable (Has some nuances)\n\n```shell\nyarn add multer\nyarn add -D @types/multer\n\nnpm install multer\nnpm install -D @types/multer\n```\n\nIn the same simple way we create a new DTO.\n\n_sign-up.dto.ts_\n\n```typescript\nimport { IsEmail, IsNotEmpty, IsNumberString, IsPhoneNumber, IsString } from \"class-validator\";\nimport { ValidatedFile, IsFiles, IsFile } from \"validness\";\n\nexport class SignUpDto {\n  // form-data text field\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  // form-data text field\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  // a single file\n  @IsFile({ type: 'image' })\n  photo: ValidatedFile\n\n  // a multiple files\n  @IsFiles({ type: 'image' })\n  documents: ValidatedFile[]\n}\n```\n\n_auth.controller.ts_\n\n```typescript\nimport { Router } from \"express\";\nimport { SignUpDto } from './sign-up.dto.ts';\nimport { validationFilePipe, DefaultFileError } from \"validness\";\nimport { StatusCodes } from \"http-status-codes\";\n\nconst router = Router()\n\n// controller\nrouter.post('/', validationFilePipe(SignUpDto), async (req, res, next) =\u003e {\n  const validatedBody = req.body as SignUpDto;\n\n  // We do not use any disk storage engines for multer\n  // So, validatedBody.photo.buffer is accessbile and stored in memory\n  // Consult API section for more details\n\n  await signUp(validatedBody);\n\n  res.json({ message: 'SUCCESS' })\n});\n\n// Error handling\nrouter.use((err, req, res, next) =\u003e {\n  // validness throws Default error models if customErrorFactory isn't sepcified.\n  // Standard models contain everything you need, like status code and errored fields\n  if (err instanceof DefaultFileError) {\n    // implement handling logic\n    res.status(StatusCodes.BAD_REQUEST).json({ message: 'ERROR' });\n  }\n});\n```\n\n#### That's it! 😊\n\n---\n\n## 🤔 Nuances I have been talking about:\n\n1. Formidable.\n\nIMO this library does not have a convenient API, therefore, some decisions were made while developing mine.\n\nIf you decide to change core config of this library (**coreConfig** property), e.g. set max size for files there and not\nin\nthe decorator, then the error thrown by formidable will **NOT** be mapped to DefaultFileError, but rather passed as is.\n\n2. Some options in configuration might not be complete, such as **mimetype** or **type**. If you hardly demand new ones,\n   just open an issue and I will expend the list within a day.\n   Same algorithm applies to any improvements you consider essential.\n\n---\n\n## 🛠️ Configuration\n\nEach validation pipe has a couple of extra arguments to customise its or underlying libraries' behaviour.\nLet's take a look at the **validationFilePipe** and **validationBodyPipe** signatures.\n\n```typescript\n// ...\nexport const validationFilePipe =\n  (DtoConstructor: ClassConstructor, config?: ValidationFileConfig): Router =\u003e {\n  }\n// ...\nexport const validationBodyPipe =\n  (DtoConstructor: ClassConstructor, config?: ValidationBodyConfig): RequestHandler =\u003e {\n  }\n// ...\n```\n\nIf you want to customise config globally for all pipes, use\n**validness** function and pass an object with options there. (Be careful with what you change in **coreConfig**)\n\n```typescript\nimport { validness } from \"validness\";\n\nvalidness({\n  // And many other options..\n  customErrorFactory: errorFactory,\n  queryValidationConfig: {\n    enableDebugMessages: true\n  }\n});\n```\n\n---\n\n## 🚀 API\n\n### ValidationConfig\n\nDefaults can be found [HERE](https://github.com/eddienubes/validness/blob/master/src/config/constants.ts)\n\nI think overall documentation for each property is not required because they're well commented in the\ncode itself.\n\nIf you feel a lack of examples - open an issue, I will add as many as you want. Thanks.\n\n---\n\n## ❤️ Contributing\n\nIf you wish to contribute to evolving of this package, please submit your issues or even open pull requests. You're\nalways welcome. 🥰\n\n---\n\n## License\n\nMIT (c) Sole Cold\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feddienubes%2Fvalidness","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feddienubes%2Fvalidness","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feddienubes%2Fvalidness/lists"}