Skip to content

Commit

Permalink
Add deserialization for primitive type.
Browse files Browse the repository at this point in the history
  • Loading branch information
Romakita committed Jan 24, 2017
1 parent 0aa7ac6 commit 0733d7c
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/constants/errors-msgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* @constructor
*/
export const BAD_REQUEST_REQUIRED = (name, expression) => `Bad request, parameter request.${name.toLowerCase().replace("parse","")}.${expression} is required.`;
export const BAD_REQUEST = (name, expression) => `Bad request, parameter request.${name.toLowerCase().replace("parse","")}.${expression}.`;
/**
*
* @param name
Expand Down
28 changes: 22 additions & 6 deletions src/controllers/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {IInvokableScope} from "../interfaces/InvokableScope";
import {BadRequest} from "ts-httpexceptions";
import {InjectorService, RequestService} from "../services";
import InjectParams from "../metadata/inject-params";
import {BAD_REQUEST_REQUIRED} from "../constants/errors-msgs";
import {BAD_REQUEST_REQUIRED, BAD_REQUEST} from "../constants/errors-msgs";
import ConverterService from "../services/converter";

export const METHODS = [
Expand Down Expand Up @@ -167,8 +167,8 @@ export class Endpoint {
}

})
.then(data => this.send(instance, data, {request, response, next}))
.catch(err => next(err));
.then(data => this.send(instance, data, {request, response, next}))
.catch(err => next(err));
};

/**
Expand Down Expand Up @@ -207,21 +207,37 @@ export class Endpoint {
/* istanbul ignore else */
if (param.name in requestService) {
paramValue = requestService[param.name].call(requestService, localScope.request, param.expression);

}

if (param.required && (paramValue === undefined || paramValue === null)) {
throw new BadRequest(BAD_REQUEST_REQUIRED(param.name, param.expression));
}

return converterService.deserialize(paramValue, param.baseType || param.use, param.use);
try {

return converterService.deserialize(paramValue, param.baseType || param.use, param.use);

} catch (err) {

/* istanbul ignore next */
if (err.name === "BAD_REQUEST") {
throw new BadRequest(BAD_REQUEST(param.name, param.expression) + " " + err.message);
} else {
/* istanbul ignore next */
(() => {
const castedError = new Error(err.message);
castedError.stack = err.stack;
throw castedError;
})();
}
}

});
}

/**
*
* @param instance
* @param targetKey
* @param localScope
* @returns {any}
*/
Expand Down
1 change: 1 addition & 0 deletions src/converters/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./primitive";
export * from "./array";
export * from "./map";
export * from "./set";
Expand Down
37 changes: 37 additions & 0 deletions src/converters/primitive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {IConverter} from "../interfaces/Converter";
import {Converter} from "../decorators/converter";
import {BadRequest} from "ts-httpexceptions";

@Converter(String, Number, Boolean)
export class PrimitiveConverter implements IConverter {

deserialize(data: string, target: any): String | Number | Boolean {

switch (target) {
case String:
return "" + data;

case Number:
const n = +data;

if (isNaN(n)) {
throw new BadRequest("Cast error. Expression value is not a number.");
}

return n;

case Boolean:

if (data === "true") return true;
if (data === "false") return false;

return !!data;

}

}

serialize(object: String | Number | Boolean): any {
return object;
}
}
20 changes: 14 additions & 6 deletions src/services/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Metadata from "../metadata/metadata";
import {CONVERTER, JSON_PROPERTIES} from "../constants/metadata-keys";
import {IJsonMetadata} from "../interfaces/JsonMetadata";
import {IConverter} from "../interfaces/Converter";
import {BadRequest} from "ts-httpexceptions";


@Service()
Expand Down Expand Up @@ -79,7 +80,7 @@ export default class ConverterService {

try {

if (isEmpty(obj) || isEmpty(targetType)) {
if (targetType !== Boolean && (isEmpty(obj) || isEmpty(targetType))) {
return obj;
}

Expand Down Expand Up @@ -126,12 +127,19 @@ export default class ConverterService {
}

} catch (err) {

/* istanbul ignore next */
(() => {
const castedError = new Error(CONVERTER_DESERIALIZE(getClassName(targetType), obj));
castedError.stack = err.stack;
throw castedError;
})();
if (err.name === "BAD_REQUEST") {
throw new BadRequest(err.message);
} else {
/* istanbul ignore next */
(() => {
const castedError = new Error(CONVERTER_DESERIALIZE(getClassName(targetType), obj));
castedError.stack = err.stack;
throw castedError;
})();
}

}


Expand Down
34 changes: 32 additions & 2 deletions test/converter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as Chai from "chai";
import {BadRequest} from "ts-httpexceptions";
import assert = require('assert');
import {inject} from '../src/testing/inject';
import {JsonProperty, ConverterService} from "../src";
Expand Down Expand Up @@ -41,6 +42,9 @@ class Foo2 {
@JsonProperty()
dateStart: Date;

@JsonProperty()
uint: number;

object: any;

@JsonProperty()
Expand All @@ -64,12 +68,38 @@ describe("ConverterService :", () => {

describe("ConverterService.deserialize", () => {

it("should do nothing when type is not deserializable", inject([ConverterService], (converterService: ConverterService) => {
it("should convert primitive type correctly", inject([ConverterService], (converterService: ConverterService) => {

expect(converterService.deserialize({}, Object)).to.be.an('object');
expect(converterService.deserialize(true, Boolean)).to.be.a('boolean');

expect(converterService.deserialize(true, Boolean)).to.be.equal(true);
expect(converterService.deserialize(false, Boolean)).to.be.equal(false);
expect(converterService.deserialize("true", Boolean)).to.be.equal(true);
expect(converterService.deserialize("false", Boolean)).to.be.equal(false);

expect(converterService.deserialize("", Boolean)).to.be.equal(false);
expect(converterService.deserialize(0, Boolean)).to.be.equal(false);
expect(converterService.deserialize(null, Boolean)).to.be.equal(false);
expect(converterService.deserialize(undefined, Boolean)).to.be.equal(false);
expect(converterService.deserialize("test", Boolean)).to.be.equal(true);

expect(converterService.deserialize("1", Number)).to.be.a('number');
expect(converterService.deserialize(1, Number)).to.be.a('number');

expect(converterService.deserialize("1", String)).to.be.a('string');
expect(converterService.deserialize(1, String)).to.be.a('string');
}));


it("should throw a BadRequest when parsing a number failed", inject([ConverterService], (converterService: ConverterService) => {

try {
converterService.deserialize("NK1", Number);
assert.ok(false);
} catch(er){
expect(er instanceof BadRequest).to.be.true;
}

}));

it("should do deserialize a date", inject([ConverterService], (converterService: ConverterService) => {
Expand Down

0 comments on commit 0733d7c

Please sign in to comment.