Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10,508 changes: 2,065 additions & 8,443 deletions package-lock.json

Large diffs are not rendered by default.

50 changes: 25 additions & 25 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nmshd/typescript-rest",
"version": "3.2.3",
"version": "3.3.0",
"description": "A Library to create RESTFul APIs with Typescript",
"keywords": [
"API",
Expand All @@ -19,8 +19,8 @@
"url": "https://github.com/nmshd/typescript-rest.git"
},
"license": "MIT",
"main": "./dist/typescript-rest.js",
"typings": "./dist/typescript-rest.d.ts",
"main": "./dist/src/typescript-rest.js",
"typings": "./dist/src/typescript-rest.d.ts",
Comment on lines +22 to +23
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it have to be /src now?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the update of TypeScript, the "rootDir" option became mandatory and therefore created the "src" directory in the dist folder.

"directories": {
"lib": "dist",
"doc": "doc"
Expand Down Expand Up @@ -61,42 +61,42 @@
},
"dependencies": {
"@types/body-parser": "1.19.6",
"@types/cookie-parser": "^1.4.9",
"@types/express": "^5.0.3",
"@types/multer": "^2.0.0",
"@types/cookie-parser": "^1.4.10",
"@types/express": "^5.0.6",
"@types/multer": "^2.1.0",
"body-parser": "^2.2.2",
"cookie-parser": "^1.4.7",
"express": "^5.2.1",
"fs-extra": "^11.3.2",
"lodash": "^4.17.23",
"multer": "^2.0.2",
"fs-extra": "^11.3.4",
"lodash": "^4.18.1",
"multer": "^2.1.1",
"reflect-metadata": "^0.2.2",
"require-glob": "^4.1.0",
"swagger-ui-express": "^5.0.1",
"yaml": "^2.8.2"
"yaml": "^2.8.3"
},
"devDependencies": {
"@js-soft/license-check": "^1.0.10",
"@nmshd/typescript-ioc": "^3.2.5",
"@types/debug": "^4.1.12",
"@types/debug": "^4.1.13",
"@types/fs-extra": "^11.0.4",
"@types/jest": "^30.0.0",
"@types/lodash": "^4.17.20",
"@types/node": "^24.7.2",
"@types/request": "^2.48.13",
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"@types/lodash": "^4.17.24",
"@types/node": "^25.6.0",
"axios": "^1.15.0",
"@typescript-eslint/eslint-plugin": "^8.58.1",
"@typescript-eslint/parser": "^8.58.1",
"cross-env": "^10.1.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jsdoc": "^48.0.4",
"eslint": "^10.2.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-jsdoc": "^62.9.0",
"eslint-plugin-prefer-arrow": "^1.2.3",
"jest": "^30.2.0",
"prettier": "^3.6.2",
"request": "^2.88.2",
"rimraf": "^6.0.1",
"ts-jest": "^29.4.5",
"typescript": "^5.9.3"
"form-data": "^4.0.5",
"jest": "^30.3.0",
"prettier": "^3.8.2",
"rimraf": "^6.1.3",
"ts-jest": "^29.4.9",
"typescript": "^6.0.2"
},
"engines": {
"node": ">=6.0.0"
Expand Down
2 changes: 1 addition & 1 deletion src/middlewares/routeRequiresAuthorization.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as debug from 'debug';
import debug from 'debug';
import { NextFunction, Request, Response } from 'express';
import * as Errors from '../server/model/errors';

Expand Down
2 changes: 1 addition & 1 deletion src/server/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as debug from 'debug';
import debug from 'debug';
import * as fs from 'fs-extra';
import * as path from 'path';
import { Server } from './server';
Expand Down
7 changes: 5 additions & 2 deletions src/server/parameter-processor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

import * as debug from 'debug';
import debug from 'debug';
import { Errors } from '../typescript-rest';
import { ParamType, ServiceProperty } from './model/metadata';
import { ParameterConverter, ServiceContext } from './model/server-types';
Expand Down Expand Up @@ -85,7 +85,7 @@ export class ParameterProcessor {
return parameterMapper;
}

private convertType(paramValue: string | boolean, paramType: Function): any {
private convertType(paramValue: string | boolean | string[], paramType: Function): any {
const serializedType = paramType['name'];
this.debugger.runtime('Processing parameter. received type: %s, received value:', serializedType, paramValue);
switch (serializedType) {
Expand All @@ -94,6 +94,9 @@ export class ParameterProcessor {
case 'Boolean':
if (paramValue === undefined) return paramValue;
if (typeof paramValue === 'boolean') return paramValue;
if (Array.isArray(paramValue)) {
throw new Errors.BadRequestError('Multiple values not allowed for boolean parameters');
}
Comment on lines 88 to +99
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

convertType() now handles string[] (and tries to reject multi-valued booleans), but the QueryParam mapper still casts context.request.query[property.name] to string, which prevents arrays from ever reaching this logic (and can still silently coerce multi-valued params). Consider passing the raw query value through (e.g., string | string[] | undefined) and extending conversion for numeric/boolean cases accordingly.

Copilot uses AI. Check for mistakes.

return paramValue.toLowerCase() === 'true';
default:
Expand Down
46 changes: 25 additions & 21 deletions src/server/server-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
'use strict';

import * as bodyParser from 'body-parser';
import * as cookieParser from 'cookie-parser';
import * as debug from 'debug';
import cookieParser from 'cookie-parser';
import debug from 'debug';
import * as express from 'express';
import * as _ from 'lodash';
import * as multer from 'multer';
import multer from 'multer';
import { routeRequiresAuthorization } from '../middlewares/routeRequiresAuthorization';
import * as Errors from './model/errors';
import { ServiceClass, ServiceMethod } from './model/metadata';
Expand Down Expand Up @@ -163,31 +163,33 @@ export class ServerContainer {
this.resolveProperties(serviceClass, serviceMethod);
}

let args: Array<any> = [serviceMethod.resolvedPath];
args = args.concat(this.buildSecurityMiddlewares(serviceClass, serviceMethod));
args = args.concat(this.buildParserMiddlewares(serviceClass, serviceMethod));
args.push(this.buildServiceMiddleware(serviceMethod, serviceClass));
const args: [string, ...Array<express.RequestHandler>] = [
serviceMethod.resolvedPath,
...this.buildSecurityMiddlewares(serviceClass, serviceMethod),
...this.buildParserMiddlewares(serviceClass, serviceMethod),
this.buildServiceMiddleware(serviceMethod, serviceClass)
];
switch (serviceMethod.httpMethod) {
case HttpMethod.GET:
this.router.get.apply(this.router, args);
this.router.get(...args);
break;
case HttpMethod.POST:
this.router.post.apply(this.router, args);
this.router.post(...args);
break;
case HttpMethod.PUT:
this.router.put.apply(this.router, args);
this.router.put(...args);
break;
case HttpMethod.DELETE:
this.router.delete.apply(this.router, args);
this.router.delete(...args);
break;
case HttpMethod.HEAD:
this.router.head.apply(this.router, args);
this.router.head(...args);
break;
case HttpMethod.OPTIONS:
this.router.options.apply(this.router, args);
this.router.options(...args);
break;
case HttpMethod.PATCH:
this.router.patch.apply(this.router, args);
this.router.patch(...args);
break;

default:
Expand Down Expand Up @@ -477,15 +479,17 @@ export class ServerContainer {
}

private buildCookieParserMiddleware() {
const args = [];
const options = this.cookiesDecoder ? { decode: this.cookiesDecoder } : undefined;
this.debugger.build('Creating cookie parser with options %j.', [this.cookiesSecret, options]);
if (this.cookiesSecret && options) {
return cookieParser(this.cookiesSecret, options);
}
if (this.cookiesSecret) {
args.push(this.cookiesSecret);
return cookieParser(this.cookiesSecret);
}
if (this.cookiesDecoder) {
args.push({ decode: this.cookiesDecoder });
if (options) {
return cookieParser(undefined, options);
}
this.debugger.build('Creating cookie parser with options %j.', args);
const middleware = cookieParser.apply(this, args);
return middleware;
return cookieParser();
}
}
5 changes: 3 additions & 2 deletions src/server/server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

import * as debug from 'debug';
import debug from 'debug';
import * as express from 'express';
import * as fs from 'fs-extra';
import * as _ from 'lodash';
Expand Down Expand Up @@ -61,8 +61,9 @@ export class Server {
} catch (e) {
serverDebugger('Error loading services for pattern: %j. Error: %o', patterns, e);
serverDebugger('ImportedTypes: %o', importedTypes);
const message = e instanceof Error ? e.message : String(e);
throw new TypeError(
`Error loading services for pattern: ${JSON.stringify(patterns)}. Error: ${e.message}`
`Error loading services for pattern: ${JSON.stringify(patterns)}. Error: ${message}`
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/server/service-invoker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

import * as debug from 'debug';
import debug from 'debug';
import * as express from 'express';
import * as _ from 'lodash';
import { Errors } from '../typescript-rest';
Expand Down
Loading
Loading