bootpress 2.0.0
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 +96 -0
- package/helpers/index.d.ts +3 -0
- package/helpers/index.js +11 -0
- package/index.d.ts +31 -0
- package/index.js +76 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<h1 align="center" style="margin-bottom: 0" >bootpress</h1>
|
|
2
|
+
<p align=center>Express but SpringBoot like</p>
|
|
3
|
+
|
|
4
|
+
## Methods
|
|
5
|
+
### **RestService**: Converts all methods to Express RequestHandlers
|
|
6
|
+
#### Basic usage:
|
|
7
|
+
```ts
|
|
8
|
+
const UserServiceImpl = {
|
|
9
|
+
users: [1, 2, 3, 4],
|
|
10
|
+
findAllUsers(): number[] {
|
|
11
|
+
return this.users;
|
|
12
|
+
},
|
|
13
|
+
findUserById(id: number) {
|
|
14
|
+
return this.users.find(user => user == id);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const UserService = RestService(UserServiceImpl);
|
|
19
|
+
|
|
20
|
+
app.get("/users", UserService.findAllUsers);
|
|
21
|
+
app.get("/users/:id", (req) => UserService.findUserById(+req.params.id));
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
#### Advanced usage:
|
|
25
|
+
```ts
|
|
26
|
+
class PostServiceImpl {
|
|
27
|
+
posts = [1, 2, 3, 4, 5];
|
|
28
|
+
findById(id: number | string) {
|
|
29
|
+
return getOrThrow(
|
|
30
|
+
this.posts.find(p => p == id),
|
|
31
|
+
new HttpError(404, "Post is not found")
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
add(id: number) {
|
|
35
|
+
this.posts.push(id);
|
|
36
|
+
return new HttpResponse(201, id);
|
|
37
|
+
}
|
|
38
|
+
delete(id: number) {
|
|
39
|
+
const idx = this.posts.indexOf(id);
|
|
40
|
+
if (idx > -1) {
|
|
41
|
+
this.posts.splice(idx, 1);
|
|
42
|
+
this.#printDeleted(id);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// use private methods to
|
|
46
|
+
#printDeleted(id: number | string) {
|
|
47
|
+
console.warn(`post ${id} is deleted`)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const PostService = RestService(new PostServiceImpl());
|
|
52
|
+
|
|
53
|
+
app.get("/posts/:id", (req) => PostService.findById(req.params.id));
|
|
54
|
+
app.post("/posts/:id", (req) => PostService.add(+req.params.id));
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### **RestMethod**: Converts single method to RequestHandler
|
|
58
|
+
#### Usage:
|
|
59
|
+
```ts
|
|
60
|
+
class UserService {
|
|
61
|
+
users = [1, 2, 3, 4];
|
|
62
|
+
findAll() {
|
|
63
|
+
return RestMethod(() => {
|
|
64
|
+
return this.users;
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
findById(id: number) {
|
|
68
|
+
return RestMethod(() => {
|
|
69
|
+
return getOrThrow(this.users.find(u => u == id), new HttpError(404, "Not Found"));
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const userService = new UserService();
|
|
75
|
+
|
|
76
|
+
app.get("/users", userService.findAll())
|
|
77
|
+
app.get("/users/:id", (req) => userService.findById(+req.params.id))
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### **Restify**: Decorator to convert a single method to RequestHandler
|
|
81
|
+
#### Note that currently decorators in Typescript doesn't support changing the return type of applied method. So you have to provide RequestHandler as an "or type":
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
class LogServiceImpl {
|
|
85
|
+
logs = ["log1", "log2", "log3"];
|
|
86
|
+
|
|
87
|
+
@Restify
|
|
88
|
+
findAll(): string[] | RequestHandler {
|
|
89
|
+
return this.logs;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const LogService = new LogServiceImpl();
|
|
94
|
+
|
|
95
|
+
app.get("/logs", LogService.findAll() as RequestHandler)
|
|
96
|
+
```
|
package/helpers/index.js
ADDED
package/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { RequestHandler } from "express"
|
|
2
|
+
|
|
3
|
+
declare class HttpError extends Error {
|
|
4
|
+
status: number
|
|
5
|
+
message: string
|
|
6
|
+
constructor(status: number, message: string)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
declare class HttpResponse<T> {
|
|
10
|
+
status: number
|
|
11
|
+
data: T
|
|
12
|
+
constructor(status: number, data: T)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type RestedService<T extends Record<string, any>> = { [K in keyof T]:
|
|
16
|
+
T[K] extends Function
|
|
17
|
+
? (...args: Parameters<T[K]>) => ((req: Request, res: Response) => void)
|
|
18
|
+
: T[K]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
declare function RestService<T extends Record<string, any>>(service: T): RestedService<T>;
|
|
22
|
+
declare function RestMethod<T>(callback: () => T): RequestHandler;
|
|
23
|
+
declare function Restify(target: any, key: string, desc: PropertyDescriptor): PropertyDescriptor;
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
HttpError,
|
|
27
|
+
HttpResponse,
|
|
28
|
+
RestService,
|
|
29
|
+
RestMethod,
|
|
30
|
+
Restify
|
|
31
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
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
|
+
function RestService(service) {
|
|
18
|
+
return Object.fromEntries(
|
|
19
|
+
Object.entries(service).map(keyvalue => {
|
|
20
|
+
if (typeof keyvalue[1] == "function") {
|
|
21
|
+
return [
|
|
22
|
+
keyvalue[0],
|
|
23
|
+
(...args) =>
|
|
24
|
+
(req, res) => {
|
|
25
|
+
try {
|
|
26
|
+
const result = keyvalue[1](...args);
|
|
27
|
+
res.status(result.status || 200).json(result.data || result);
|
|
28
|
+
} catch (e) {
|
|
29
|
+
res.status(e.status || 500).json(e.message || e);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
} else {
|
|
34
|
+
return keyvalue;
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function RestMethod(callback) {
|
|
41
|
+
return (req, res) => {
|
|
42
|
+
try {
|
|
43
|
+
const result = callback();
|
|
44
|
+
res.status(result.status || 200).json(result.data || result);
|
|
45
|
+
return result;
|
|
46
|
+
} catch (e) {
|
|
47
|
+
res.status(e.status || 500).json(e.message || e);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function Restify(target, key, desc) {
|
|
53
|
+
const oldFunc = desc.value;
|
|
54
|
+
return {
|
|
55
|
+
...desc,
|
|
56
|
+
value: (...args) => {
|
|
57
|
+
return (req, res) => {
|
|
58
|
+
try {
|
|
59
|
+
const result = oldFunc(...args);
|
|
60
|
+
res.status(result.status || 200).json(result.data || result);
|
|
61
|
+
return result;
|
|
62
|
+
} catch (e) {
|
|
63
|
+
res.status(e.status || 500).json(e.message || e);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = {
|
|
71
|
+
HttpError,
|
|
72
|
+
HttpResponse,
|
|
73
|
+
RestService,
|
|
74
|
+
RestMethod,
|
|
75
|
+
Restify
|
|
76
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bootpress",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "REST service methods for express",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {},
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/ufukbakan/bootpress.git"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"bootpress",
|
|
13
|
+
"express",
|
|
14
|
+
"rest",
|
|
15
|
+
"service",
|
|
16
|
+
"methods",
|
|
17
|
+
"spring",
|
|
18
|
+
"boot",
|
|
19
|
+
"like"
|
|
20
|
+
],
|
|
21
|
+
"author": "Ufuk Bakan",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/ufukbakan/bootpress/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/ufukbakan/bootpress#readme",
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/express": "^4.17.17"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"express": "^4.18.2"
|
|
32
|
+
}
|
|
33
|
+
}
|