bootpress 5.0.1 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,11 @@
1
1
  <h1 align="center" style="margin-bottom: 0" >
2
- <img src="bootpress.svg" height=120 alt="bootpress">
2
+ <img src="https://raw.githubusercontent.com/ufukbakan/bootpress/main/bootpress.svg" height=120 alt="bootpress">
3
3
  </h1>
4
4
  <p align=center>Express but Spring Boot like</p>
5
5
 
6
+ ## Quick Start
7
+ Recommended tool: [create-bootpress-app](https://www.npmjs.com/package/create-bootpress-app)
8
+
6
9
  ## Methods
7
10
  ### **<u>RestService</u>**: Converts all methods to Express RequestHandlers
8
11
  #### Basic usage:
@@ -1,4 +1,4 @@
1
- import { HttpError } from "..";
1
+ import { HttpError } from "../types";
2
2
 
3
3
  type TypeMap = {
4
4
  "string": string,
@@ -10,7 +10,7 @@ type TypeMap = {
10
10
  }
11
11
 
12
12
  type ValidTypeKeys = keyof TypeMap;
13
- type ValOf<T extends keyof TypeMap> = TypeMap[T]
13
+ type ValOf<T extends ValidTypeKeys> = TypeMap[T]
14
14
 
15
15
  type StringEndsWithQm = `${string}?`;
16
16
 
@@ -35,4 +35,27 @@ export function asNumber(o: any): number;
35
35
  export function asInteger(o: any): number;
36
36
  export function asString(o: any): string;
37
37
  export function asSchema<T extends JsSchema>(o: any, jsSchema: T): TypedSchema<T>;
38
- export function schema<T extends JsSchema>(schema: T): T;
38
+ export function schema<T extends JsSchema>(schema: T): T;
39
+
40
+ type ExtendedTypeMap = {
41
+ "string": string,
42
+ "string[]": string[],
43
+ "boolean": boolean,
44
+ "boolean[]": boolean[],
45
+ "number": number,
46
+ "number[]": number[],
47
+ "integer": number,
48
+ "integer[]": number[],
49
+ "string?": string | null,
50
+ "string[]?": string[] | null,
51
+ "boolean?": boolean | null,
52
+ "boolean[]?": boolean[] | null,
53
+ "number?": number | null,
54
+ "number[]?": number[] | null,
55
+ "integer?": number | null,
56
+ "integer[]?": number[] | null
57
+ }
58
+
59
+ type ExtendedTypeKeys = keyof ExtendedTypeMap;
60
+ type ExtValOf<T extends ExtendedTypeKeys> = ExtendedTypeMap[T]
61
+ export function as<T extends (ExtendedTypeKeys | JsSchema | ArraySchema)>(o:any, schema: T): T extends ExtendedTypeKeys ? ExtValOf<T> : TypedSchema<T>;
package/helpers/index.js CHANGED
@@ -1,4 +1,4 @@
1
- const { HttpError } = require("..");
1
+ const { HttpError } = require("../types");
2
2
 
3
3
  function getOrThrow(data, error) {
4
4
  if (data === null || data === undefined) {
@@ -34,6 +34,9 @@ function asBoolean(o, errorMessage = undefined, errorStatus = 400) {
34
34
  return validBooleanStrings.get(lowercased);
35
35
  } else if (typeof o === "boolean") {
36
36
  return o;
37
+ } else if (typeof o === "number"){
38
+ if(o === 1) return true;
39
+ if(o === 0) return false;
37
40
  }
38
41
  throw new HttpError(errorStatus, errorMessage);
39
42
  }
@@ -102,8 +105,8 @@ function asSchema(o, schema) {
102
105
  else if (typeof expectedType === "string") {
103
106
  if (expectedType.endsWith("[]")) {
104
107
  const elementType = expectedType.replace("[]", "");
105
- for (let j = 0; j < o[key].length; j++){
106
- if(typeof o[key][j] !== elementType){
108
+ for (let j = 0; j < o[key].length; j++) {
109
+ if (typeof o[key][j] !== elementType) {
107
110
  throw new HttpError(400, `Each element of ${key} should have been a ${elementType} but a ${typeof o[key][j]} is present (${o[key][j]})`);
108
111
  }
109
112
  }
@@ -127,6 +130,73 @@ function schema(schema) {
127
130
  return schema;
128
131
  }
129
132
 
133
+ function asArrayOf(o, elementType) {
134
+ if (Array.isArray(o)) {
135
+ for (let i = 0; i < o.length; i++) {
136
+ if(elementType === "integer"){
137
+ asInteger(o[i]);
138
+ }else if(typeof o[i] != elementType){
139
+ throw new HttpError(400, `Each element in array should have been a ${elementType} but ${o[i]} is present with type ${typeof o[i]}`);
140
+ }
141
+ }
142
+ return o;
143
+ } else {
144
+ throw new HttpError(400, `Provided object is not an array: ${JSON.stringify(o)}`)
145
+ }
146
+ }
147
+
148
+ function as(o, type) {
149
+ if (typeof type == "string") {
150
+ if (type.endsWith("[]")) {
151
+ // array check
152
+ const elementType = type.replace("[]", "");
153
+ return asArrayOf(o, elementType);
154
+ } else {
155
+ if(type.endsWith("?") && o == null){
156
+ return null;
157
+ }else if(type.endsWith("?") && o != null ){
158
+ const actualType = type.replace("?", "");
159
+ return as(o, actualType);
160
+ }
161
+ // primitive check
162
+ switch (type) {
163
+ case "string":
164
+ return asString(o);
165
+ case "number":
166
+ return asNumber(o);
167
+ case "boolean":
168
+ return asBoolean(o);
169
+ case "integer":
170
+ return asInteger(o);
171
+ default:
172
+ throw new HttpError(500, `Unsupported type ${type}`);
173
+ }
174
+ }
175
+ } else if (typeof type == "object" && type != null) {
176
+ if (Array.isArray(type)) {
177
+ if(type.length > 1){
178
+ throw new HttpError(500, `You can define only one schema for types ArrayOf<Schema>`);
179
+ }else if (type.length < 1){
180
+ throw new HttpError(500, `You must define a schema for types ArrayOf<Schema>`);
181
+ }
182
+ // array schema validation
183
+ if(!Array.isArray(o)){
184
+ throw new HttpError(400, `Provided value should have been an array. (${JSON.stringify(o)})`)
185
+ }
186
+ const providedSchema = type[0];
187
+ for(let i = 0; i < o.length; i++){
188
+ asSchema(o[i], providedSchema);
189
+ }
190
+ return o;
191
+ } else {
192
+ // schema validation
193
+ return asSchema(o, type);
194
+ }
195
+ } else {
196
+ throw new HttpError(500, `Unsupported type check ${type}`)
197
+ }
198
+ }
199
+
130
200
  module.exports = {
131
201
  getOrThrow,
132
202
  getOrElse,
@@ -135,5 +205,6 @@ module.exports = {
135
205
  asInteger,
136
206
  asString,
137
207
  asSchema,
138
- schema
208
+ schema,
209
+ as
139
210
  }
package/index.d.ts CHANGED
@@ -1,21 +1,9 @@
1
- import { Response } from "express"
2
- import { Request } from "express"
1
+ import { Response, Request } from "express"
2
+ import { ArraySchema, JsSchema, ValidTypeKeys } from "./helpers"
3
3
 
4
4
  type RequestHandler = (req: Request, res: Response) => void
5
5
  type RequsetHandlerWithArgs = (...args: any[]) => RequestHandler
6
6
 
7
- declare class HttpError extends Error {
8
- status: number
9
- message: string
10
- constructor(status: number, message: string)
11
- }
12
-
13
- declare class HttpResponse<T> {
14
- status: number
15
- data: T
16
- constructor(status: number, data: T)
17
- }
18
-
19
7
  type RestedService<T extends Record<string, any>> = { [K in keyof T]:
20
8
  T[K] extends Function
21
9
  ? (...args: Parameters<T[K]>) => RequestHandler
@@ -28,17 +16,17 @@ declare function RestMethod<T>(callback: () => T): RequestHandler;
28
16
  declare function Restify(target: any, key: string, desc: PropertyDescriptor): PropertyDescriptor;
29
17
 
30
18
  declare function PassBody(serviceFunction: RequestHandler | RequsetHandlerWithArgs): RequestHandler
31
- declare function PassRequest(serviceFunction: RequestHandler | RequsetHandlerWithArgs): RequestHandler
19
+ declare function PassBodyAs(type: ValidTypeKeys | JsSchema | ArraySchema ): (serviceFunction: RequestHandler | RequsetHandlerWithArgs) => RequestHandler
32
20
  declare function PassAllParams(serviceFunction: RequestHandler | RequsetHandlerWithArgs): RequestHandler
33
21
  declare function PassAllQueries(serviceFunction: RequestHandler | RequsetHandlerWithArgs): RequestHandler
34
22
  declare function PassAllCookies(serviceFunction: RequestHandler | RequsetHandlerWithArgs): RequestHandler
35
23
  declare function PassParams(...paramNames: string[]): (serviceFunction: RequestHandler | RequsetHandlerWithArgs) => RequestHandler
36
24
  declare function PassQueries(...queryNames: string[]): (serviceFunction: RequestHandler | RequsetHandlerWithArgs) => RequestHandler
37
- declare function PassCookies(...cookieNames: string[]): (serviceFunction: RequestHandler |RequsetHandlerWithArgs) => RequestHandler
25
+ declare function PassCookies(...cookieNames: string[]): (serviceFunction: RequestHandler | RequsetHandlerWithArgs) => RequestHandler
26
+ declare function PassRequest(serviceFunction: RequestHandler | RequsetHandlerWithArgs): RequestHandler
27
+ declare function PassResponse(serviceFunction: RequestHandler | RequsetHandlerWithArgs): RequestHandler
38
28
 
39
29
  export {
40
- HttpError,
41
- HttpResponse,
42
30
  RestService,
43
31
  RestMethod,
44
32
  Restify,
@@ -49,5 +37,7 @@ export {
49
37
  PassCookies,
50
38
  PassAllCookies,
51
39
  PassBody,
52
- PassRequest
40
+ PassBodyAs,
41
+ PassRequest,
42
+ PassResponse
53
43
  }
package/index.js CHANGED
@@ -1,18 +1,5 @@
1
- class HttpError extends Error {
2
- constructor(status, message) {
3
- super(message);
4
- this.stack += "\n" + message;
5
- this.message = message;
6
- this.status = status;
7
- }
8
- }
9
-
10
- class HttpResponse {
11
- constructor(status, data) {
12
- this.status = status;
13
- this.data = data;
14
- }
15
- }
1
+ const { as } = require("./helpers");
2
+ const { HttpError } = require("./types");
16
3
 
17
4
  const protectedProperties = [
18
5
  "toString",
@@ -21,6 +8,14 @@ const protectedProperties = [
21
8
  "toLocaleString"
22
9
  ]
23
10
 
11
+ function reply(res, status, data) {
12
+ if (typeof data == "object") {
13
+ res.status(status).json(data);
14
+ } else {
15
+ res.status(status).send(data);
16
+ }
17
+ }
18
+
24
19
  function RestService(service) {
25
20
  if (typeof service == "function") {
26
21
  try {
@@ -49,9 +44,9 @@ function RestService(service) {
49
44
  } else if (result === null) {
50
45
  throw new HttpError(200, "Your method is executed but it returned null. At least a value is expected to be returned.");
51
46
  }
52
- res.status(result.status || 200).json(result.data || result);
47
+ reply(res, result.status || 200, result.data || result)
53
48
  } catch (e) {
54
- res.status(e.status || 500).send(e.message || e);
49
+ reply(res, e.status || 500, e.message || e);
55
50
  }
56
51
  }),
57
52
  configurable: keyvalue[1].configurable,
@@ -71,10 +66,10 @@ function RestMethod(callback) {
71
66
  return (req, res) => {
72
67
  try {
73
68
  const result = callback();
74
- res.status(result.status || 200).json(result.data || result);
69
+ reply(res, result.status || 200, result.data || result);
75
70
  return result;
76
71
  } catch (e) {
77
- res.status(e.status || 500).json(e.message || e);
72
+ reply(res, e.status || 500, e.message || e)
78
73
  }
79
74
  }
80
75
  }
@@ -87,10 +82,10 @@ function Restify(target, key, desc) {
87
82
  return (req, res) => {
88
83
  try {
89
84
  const result = oldFunc(...args);
90
- res.status(result.status || 200).json(result.data || result);
85
+ reply(res, result.status || 200, result.data || result);
91
86
  return result;
92
87
  } catch (e) {
93
- res.status(e.status || 500).json(e.message || e);
88
+ reply(res, e.status || 500, e.message || e);
94
89
  }
95
90
  }
96
91
  }).bind(target)
@@ -171,6 +166,30 @@ function PassBody(actualHandler) {
171
166
  }
172
167
  }
173
168
 
169
+ function PassBodyAs(type) {
170
+ return (actualHandler) => {
171
+ return (...args) => {
172
+ if (isRequstHandlerArgs(args)) {
173
+ const req = args.at(-3); const res = args.at(-2);
174
+ try {
175
+ return actualHandler(as(req.body, type))(req, res);
176
+ } catch (e) {
177
+ reply(res, e.status || 500, e.message || e);
178
+ }
179
+
180
+ } else {
181
+ return (req, res) => {
182
+ try{
183
+ return actualHandler(...args, as(req.body, type))(req, res);
184
+ }catch(e){
185
+ reply(res, e.status || 500, e.message || e)
186
+ }
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
192
+
174
193
  function PassRequest(actualHandler) {
175
194
  return (...args) => {
176
195
  if (isRequstHandlerArgs(args)) {
@@ -182,6 +201,17 @@ function PassRequest(actualHandler) {
182
201
  }
183
202
  }
184
203
 
204
+ function PassResponse(actualHandler) {
205
+ return (...args) => {
206
+ if (isRequstHandlerArgs(args)) {
207
+ const req = args.at(-3); const res = args.at(-2);
208
+ return actualHandler(res)(req, res);
209
+ } else {
210
+ return (req, res) => actualHandler(...args, res)(req, res)
211
+ }
212
+ }
213
+ }
214
+
185
215
  function PassAllCookies(actualHandler) {
186
216
  return (...args) => {
187
217
  if (isRequstHandlerArgs(args)) {
@@ -208,8 +238,6 @@ function PassCookies(...cookieNames) {
208
238
  }
209
239
 
210
240
  module.exports = {
211
- HttpError,
212
- HttpResponse,
213
241
  RestService,
214
242
  RestMethod,
215
243
  Restify,
@@ -220,5 +248,7 @@ module.exports = {
220
248
  PassAllCookies,
221
249
  PassCookies,
222
250
  PassBody,
223
- PassRequest
251
+ PassBodyAs,
252
+ PassRequest,
253
+ PassResponse
224
254
  }
package/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "bootpress",
3
- "version": "5.0.1",
3
+ "version": "6.0.1",
4
4
  "description": "REST service methods for express",
5
5
  "main": "index.js",
6
- "scripts": {},
7
6
  "repository": {
8
7
  "type": "git",
9
8
  "url": "git+https://github.com/ufukbakan/bootpress.git"
@@ -28,7 +27,7 @@
28
27
  "express": "^4.18.2"
29
28
  },
30
29
  "devDependencies": {
31
- "@types/body-parser": "^1.19.2",
32
- "@types/express": "^4.17.17"
30
+ "@types/express": "^4.17.17",
31
+ "typescript": "^4.9.5"
33
32
  }
34
33
  }
package/types/index.js ADDED
@@ -0,0 +1,20 @@
1
+ class HttpError extends Error {
2
+ constructor(status, message) {
3
+ super(message);
4
+ this.stack += "\n" + message;
5
+ this.message = message;
6
+ this.status = status;
7
+ }
8
+ }
9
+
10
+ class HttpResponse {
11
+ constructor(status, data) {
12
+ this.status = status;
13
+ this.data = data;
14
+ }
15
+ }
16
+
17
+ module.exports = {
18
+ HttpError,
19
+ HttpResponse
20
+ }
package/types/index.ts ADDED
@@ -0,0 +1,16 @@
1
+ declare class HttpError extends Error {
2
+ status: number
3
+ message: string
4
+ constructor(status: number, message: string)
5
+ }
6
+
7
+ declare class HttpResponse<T> {
8
+ status: number
9
+ data: T
10
+ constructor(status: number, data: T)
11
+ }
12
+
13
+ export {
14
+ HttpError,
15
+ HttpResponse
16
+ }