Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit 5409c88

Browse files
committed
Init
0 parents  commit 5409c88

File tree

11 files changed

+7823
-0
lines changed

11 files changed

+7823
-0
lines changed

.github/workflows/main.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: CI
2+
on: [push]
3+
jobs:
4+
build:
5+
name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }}
6+
7+
runs-on: ${{ matrix.os }}
8+
strategy:
9+
matrix:
10+
node: ['10.x', '12.x', '14.x']
11+
os: [ubuntu-latest, windows-latest, macOS-latest]
12+
13+
steps:
14+
- name: Checkout repo
15+
uses: actions/checkout@v2
16+
17+
- name: Use Node ${{ matrix.node }}
18+
uses: actions/setup-node@v1
19+
with:
20+
node-version: ${{ matrix.node }}
21+
22+
- name: Install deps and build (with cache)
23+
uses: bahmutov/npm-install@v1
24+
25+
- name: Lint
26+
run: yarn lint
27+
28+
- name: Test
29+
run: yarn test --ci --coverage --maxWorkers=2
30+
31+
- name: Build
32+
run: yarn build

.github/workflows/size.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: size
2+
on: [pull_request]
3+
jobs:
4+
size:
5+
runs-on: ubuntu-latest
6+
env:
7+
CI_JOB_NUMBER: 1
8+
steps:
9+
- uses: actions/checkout@v1
10+
- uses: andresz1/size-limit-action@v1
11+
with:
12+
github_token: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.log
2+
.DS_Store
3+
node_modules
4+
dist

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Alireza Zamani
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Better Validation Pipe
2+
3+
This pipe extends Nest's [built-in validation pipe](https://docs.nestjs.com/techniques/validation#using-the-built-in-validationpipe) and makes it a bit more descriptive.
4+
5+
## Introduction
6+
7+
The default validation pipe is great, but error it returns is just an array of errors:
8+
9+
```json
10+
{
11+
"statusCode": 400,
12+
"error": "Bad Request",
13+
"message": ["email must be an email", "phone cannot be empty"]
14+
}
15+
```
16+
17+
This package changes the `message` to be an object with field names as keys:
18+
19+
```json
20+
{
21+
"statusCode": 400,
22+
"error": "Bad Request",
23+
"message": {
24+
"email": ["email must be an email"],
25+
"phone": ["phone cannot be empty"]
26+
}
27+
}
28+
```
29+
30+
So then, on your frontend, you can show each error next to its relavant field, instead of showing all of them at the end of your form
31+
32+
## Installation
33+
34+
On Yarn:
35+
36+
```shell
37+
yarn add @nestray/better-validation-pipe
38+
```
39+
40+
On NPM:
41+
42+
```shell
43+
npm install @nestray/better-validation-pipe
44+
```
45+
46+
## Motivation
47+
48+
This behavior is achievable by passing a custom `exceptionFactory` to the original pipe, but I found myself writing the same exception factory for each one of my projects, so I made this small package.

package.json

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"version": "0.1.0",
3+
"license": "MIT",
4+
"main": "dist/index.js",
5+
"typings": "dist/index.d.ts",
6+
"files": [
7+
"dist",
8+
"src"
9+
],
10+
"engines": {
11+
"node": ">=10"
12+
},
13+
"repository": {
14+
"url": "https://github.com/NestRay/better-validation-pipe"
15+
},
16+
"scripts": {
17+
"start": "tsdx watch",
18+
"build": "tsdx build",
19+
"test": "tsdx test",
20+
"lint": "tsdx lint",
21+
"prepare": "tsdx build",
22+
"size": "size-limit",
23+
"analyze": "size-limit --why"
24+
},
25+
"peerDependencies": {},
26+
"husky": {
27+
"hooks": {
28+
"pre-commit": "tsdx lint"
29+
}
30+
},
31+
"prettier": {
32+
"printWidth": 80,
33+
"semi": true,
34+
"singleQuote": true,
35+
"trailingComma": "es5"
36+
},
37+
"name": "@nestray/better-validation-pipe",
38+
"author": {
39+
"name": "Alireza Zamani",
40+
"email": "alirezazamani2922@gmail.com"
41+
},
42+
"module": "dist/better-validation-pipe.esm.js",
43+
"size-limit": [
44+
{
45+
"path": "dist/better-validation-pipe.cjs.production.min.js",
46+
"limit": "10 KB"
47+
},
48+
{
49+
"path": "dist/better-validation-pipe.esm.js",
50+
"limit": "10 KB"
51+
}
52+
],
53+
"devDependencies": {
54+
"@size-limit/preset-small-lib": "^6.0.4",
55+
"husky": "^7.0.4",
56+
"size-limit": "^6.0.4",
57+
"tsdx": "^0.14.1",
58+
"tslib": "^2.3.1",
59+
"typescript": "^4.4.4"
60+
},
61+
"dependencies": {
62+
"@nestjs/common": "^8.2.0",
63+
"reflect-metadata": "^0.1.13"
64+
}
65+
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './validation.pipe';

src/validation.pipe.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { ValidationPipe } from './validation.pipe';
2+
3+
describe('Validation pipe', () => {
4+
it('is defined', () => {
5+
expect(ValidationPipe).toBeDefined();
6+
});
7+
});

src/validation.pipe.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import {
2+
ValidationError,
3+
ValidationPipe as OriginalValidationPipe,
4+
} from '@nestjs/common';
5+
import { HttpErrorByCode } from '@nestjs/common/utils/http-error-by-code.util';
6+
7+
export class ValidationPipe extends OriginalValidationPipe {
8+
public createExceptionFactory() {
9+
return (validationErrors: ValidationError[] = []) => {
10+
if (this.isDetailedOutputDisabled) {
11+
return new HttpErrorByCode[this.errorHttpStatusCode]();
12+
}
13+
const errors: Record<string, unknown> = {};
14+
validationErrors.forEach(error => {
15+
errors[error.property] = Object.values(error.constraints || {});
16+
});
17+
return new HttpErrorByCode[this.errorHttpStatusCode](errors);
18+
};
19+
}
20+
}

tsconfig.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
// see https://www.typescriptlang.org/tsconfig to better understand tsconfigs
3+
"include": ["src", "types"],
4+
"compilerOptions": {
5+
"module": "esnext",
6+
"lib": ["dom", "esnext"],
7+
"importHelpers": true,
8+
// output .d.ts declaration files for consumers
9+
"declaration": true,
10+
// output .js.map sourcemap files for consumers
11+
"sourceMap": true,
12+
// match output dir to input dir. e.g. dist/index instead of dist/src/index
13+
"rootDir": "./src",
14+
// stricter type-checking for stronger correctness. Recommended by TS
15+
"strict": true,
16+
// linter checks for common issues
17+
"noImplicitReturns": true,
18+
"noFallthroughCasesInSwitch": true,
19+
// noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative
20+
"noUnusedLocals": true,
21+
"noUnusedParameters": true,
22+
// use Node's module resolution algorithm, instead of the legacy TS one
23+
"moduleResolution": "node",
24+
// transpile JSX to React.createElement
25+
"jsx": "react",
26+
// interop between ESM and CJS modules. Recommended by TS
27+
"esModuleInterop": true,
28+
// significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS
29+
"skipLibCheck": true,
30+
// error out if import and file system have a casing mismatch. Recommended by TS
31+
"forceConsistentCasingInFileNames": true,
32+
// `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc`
33+
"noEmit": true,
34+
}
35+
}

0 commit comments

Comments
 (0)