Skip to content

Commit

Permalink
API changes + enhanced error throwing
Browse files Browse the repository at this point in the history
- changes object parameter type to `object`
- throwing error while passing array, null or undefined
- updated readme
- bumped version to 0.2.0
  • Loading branch information
MichalLytek committed Feb 24, 2017
1 parent a6203a4 commit 11ad158
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 41 deletions.
26 changes: 18 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ async (req, res) => {

There is available one function with two overloads:
```typescript
function transformAndValidate<T extends PlainObject>(classType: ClassType<T>, jsonString: string, options?: TransformValdiationOptions): Promise<T>;
function transformAndValidate<T extends object>(classType: ClassType<T>, jsonString: string, options?: TransformValdiationOptions): Promise<T>;
```

```typescript
function transformAndValidate<T extends PlainObject>(classType: ClassType<T>, object: PlainObject, options?: TransformValdiationOptions): Promise<T>;
function transformAndValidate<T extends object>(classType: ClassType<T>, object: object, options?: TransformValdiationOptions): Promise<T>;
```

#### Parameters and types
Expand All @@ -85,12 +85,7 @@ type ClassType<T> = {
```
- `jsonString` - a normal string containing JSON
- `object` - plain JS object with some properties (not empty - `{}`). `PlainObject` is a defined as normal JS object type but with some properties defined, to provide compile-time error when e.g. number is passed as parameter:
```typescript
type PlainObject = {
[property: string]: any;
}
```
- `object` - plain JS object of type `object` (introduced in TypeScript 2.1), you will have compile-time error while trying to pass number, boolean, null or undefined but unfortunately run-time error when passing a function or an array
- `options` - optional options object, it has two optional properties
```typescript
Expand All @@ -104,3 +99,18 @@ You can use it to pass options for `class-validator` ([more info](https://github
## More info

The [class-transformer](https://github.com/pleerock/class-transformer) and [class-validator](https://github.com/pleerock/class-validator) are more powerfull than it was showed in the simple usage sample, so go to their github page and check out they capabilities!

## Release notes

**0.2.0**

* changed object parameter type declaration to `object` (introduced in TS 2.2)
* throwing error when passed array, undefined or null

**0.1.1**

* changed throwing error (rejecting promise) [from string to `Error` with message](https://github.com/19majkel94/class-transformer-validator/commit/e0ed33f9f8feb58d52bfdbc78f8150cdfd0ebe77#diff-f41e9d04a45c83f3b6f6e630f10117feR39)

**0.1.0**

* initial version with `transformAndValidate` function
19 changes: 16 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "class-transformer-validator",
"version": "0.1.1",
"version": "0.2.0",
"description": "A simple wrapper around class-transformer and class-validator which provides nice and programmer-friendly API.",
"license": "MIT",
"readmeFilename": "README.md",
Expand All @@ -19,7 +19,19 @@
"class-validator",
"validator",
"validation",
"typescript-validator",
"class-transformer",
"serialization",
"deserialization",
"serializer",
"typescript",
"object-to-class",
"typescript-serializer"
],
"keywords": [
"class-validator",
"validator",
"validation",
"typescript-validator",
"class-transformer",
"serialization",
Expand All @@ -38,7 +50,7 @@
"class-transformer": "^0.1.6",
"class-validator": "^0.6.8",
"mocha": "^3.2.0",
"typescript": "^2.1.5"
"typescript": "^2.2.1"
},
"peerDependencies": {
"class-validator": "^0.6.8",
Expand All @@ -49,5 +61,6 @@
"pretest": "npm run build",
"test": "mocha build/tests/index.js",
"build": "tsc"
}
},
"private": true
}
43 changes: 24 additions & 19 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,48 @@ import { plainToClass, ClassTransformOptions } from "class-transformer";
export type ClassType<T> = {
new (...args: any[]): T;
}
export type PlainObject = {
[property: string]: any;
}

export interface TransformValdiationOptions {
validator?: ValidatorOptions;
transformer?: ClassTransformOptions;
}

/**
* Converts JSON string to class (constructor) object.
* Asynchronously converts JSON string to class (constructor) object
*
* @param {ClassType<T>} classType The Class to parse and convert JSON to.
* @return {Promise<T>} Promise of object of given class.
* @export
* @template T
* @param {ClassType<T>} classType The Class to parse and convert JSON to
* @param {string} jsonString The string containing JSON
* @param {TransformValdiationOptions} [options] Optional options object for class-validator and class-transformer
* @returns {Promise<T>} Promise of object of given class T
*/
export function transformAndValidate<T extends PlainObject>(classType: ClassType<T>, jsonString: string, options?: TransformValdiationOptions): Promise<T>;
export function transformAndValidate<T extends object>(classType: ClassType<T>, jsonString: string, options?: TransformValdiationOptions): Promise<T>;
/**
* Converts plain object to class (constructor) object.
* Asynchronously converts plain object to class (constructor) object
*
* @param {ClassType<T>} classType The Class to convert object to.
* @return {Promise<T>} Promise of object of given class.
* @export
* @template T
* @param {ClassType<T>} classType The Class to convert object to
* @param {object} object The object to instantiate and validate
* @param {TransformValdiationOptions} [options] Optional options object for class-validator and class-transformer
* @returns {Promise<T>} Promise of object of given class T
*/
export function transformAndValidate<T extends PlainObject>(classType: ClassType<T>, object: PlainObject, options?: TransformValdiationOptions): Promise<T>;
export function transformAndValidate<T extends object>(classType: ClassType<T>, object: object, options?: TransformValdiationOptions): Promise<T>;

export function transformAndValidate<T extends PlainObject>(classType: ClassType<T>, objectOrString: PlainObject|string, options?: TransformValdiationOptions): Promise<T> {
export function transformAndValidate<T extends object>(classType: ClassType<T>, somethingToTransform: object|string, options?: TransformValdiationOptions): Promise<T> {
return new Promise((resolve, reject) => {
let object: Object;
if (typeof objectOrString === "string") {
object = JSON.parse(objectOrString);
} else if (typeof objectOrString === "object") {
object = objectOrString;
let object: object;
if (typeof somethingToTransform === "string") {
object = JSON.parse(somethingToTransform);
} else if (typeof somethingToTransform === "object" && somethingToTransform !== null && !Array.isArray(somethingToTransform)) {
object = somethingToTransform;
} else {
return reject(new Error("Incorrect object param type! Only strings and plain objects are valid."));
}

const classObject = plainToClass(classType, object, options ? options.transformer : undefined);
validateOrReject(classObject, options ? options.validator : undefined)
const classObject = plainToClass(classType, object, options ? options.transformer : void 0);
validateOrReject(classObject, options ? options.validator : void 0)
.then(() => resolve(classObject))
.catch(reject);
});
Expand Down
38 changes: 27 additions & 11 deletions src/tests/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { ValidationError, IsEmail } from 'class-validator';
import { transformAndValidate } from "../index";

import { expect } from "chai";
import * as chai from "chai";
import { expect, use } from "chai";
import * as chaiAsPromised from "chai-as-promised";
chai.use(chaiAsPromised);

use(chaiAsPromised);

class User {
@IsEmail()
Expand Down Expand Up @@ -42,6 +40,16 @@ describe("transformAndValidate()", () => {
expect(transformedUser.greet()).to.equals("Greeting");
});

it("should throw ValidationError array when object property is not passing validation", async () => {
const user = {
email: "test@test"
} as User;

const error = await expect(transformAndValidate(User, user)).to.be.rejected;
expect(error).to.have.lengthOf(1);
expect(error[0]).to.be.instanceOf(ValidationError);
});

it("should throw SyntaxError while parsing invalid JSON string", async () => {
const userJson = JSON.stringify(user) + "error";

Expand All @@ -63,19 +71,27 @@ describe("transformAndValidate()", () => {
expect(error.message).to.equals(rejectMessage);
});

it("should throw Error when object parameter is an array", async () => {
const error: Error = await expect(transformAndValidate(User, [])).to.be.rejected;
expect(error).to.exist;
expect(error.message).to.equals(rejectMessage);
});

it("should throw Error when object parameter is a boolean value", async () => {
const error: Error = await expect(transformAndValidate(User, true as any)).to.be.rejected;
expect(error).to.exist;
expect(error.message).to.equals(rejectMessage);
});

it("should throw ValidationError array when object property is not passing validation", async () => {
const user = {
email: "test@test"
} as User;
it("should throw Error when object parameter is a null", async () => {
const error: Error = await expect(transformAndValidate(User, null as any)).to.be.rejected;
expect(error).to.exist;
expect(error.message).to.equals(rejectMessage);
});

const error = await expect(transformAndValidate(User, user)).to.be.rejected;
expect(error).to.have.lengthOf(1);
expect(error[0]).to.be.instanceOf(ValidationError);
it("should throw Error when object parameter is an undefined", async () => {
const error: Error = await expect(transformAndValidate(User, void 0 as any)).to.be.rejected;
expect(error).to.exist;
expect(error.message).to.equals(rejectMessage);
});
});

0 comments on commit 11ad158

Please sign in to comment.