@feathersjs/express 5.0.0-pre.2 → 5.0.0-pre.20
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/CHANGELOG.md +187 -0
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/lib/authentication.d.ts +5 -6
- package/lib/authentication.js +28 -42
- package/lib/authentication.js.map +1 -1
- package/lib/declarations.d.ts +17 -12
- package/lib/index.d.ts +5 -5
- package/lib/index.js +60 -60
- package/lib/index.js.map +1 -1
- package/lib/rest.d.ts +8 -20
- package/lib/rest.js +60 -122
- package/lib/rest.js.map +1 -1
- package/package.json +23 -20
- package/src/authentication.ts +38 -48
- package/src/declarations.ts +28 -25
- package/src/handlers.ts +4 -4
- package/src/index.ts +44 -32
- package/src/rest.ts +78 -128
package/src/index.ts
CHANGED
|
@@ -1,25 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
} from '
|
|
5
|
-
import {
|
|
6
|
-
Application as FeathersApplication, defaultServiceMethods
|
|
7
|
-
} from '@feathersjs/feathers';
|
|
1
|
+
import express, { Express } from 'express';
|
|
2
|
+
import { Application as FeathersApplication, defaultServiceMethods } from '@feathersjs/feathers';
|
|
3
|
+
import { routing } from '@feathersjs/transport-commons';
|
|
4
|
+
import { createDebug } from '@feathersjs/commons';
|
|
8
5
|
|
|
9
6
|
import { Application } from './declarations';
|
|
10
|
-
import { errorHandler, notFound } from './handlers';
|
|
11
|
-
import { parseAuthentication, authenticate } from './authentication';
|
|
12
7
|
|
|
13
|
-
export {
|
|
14
|
-
_static as static, json, raw, text, urlencoded, query,
|
|
15
|
-
errorHandler, notFound, express as original,
|
|
16
|
-
authenticate, parseAuthentication
|
|
17
|
-
};
|
|
8
|
+
export { default as original, static, static as serveStatic, json, raw, text, urlencoded, query } from 'express';
|
|
18
9
|
|
|
19
|
-
export * from './
|
|
10
|
+
export * from './authentication';
|
|
20
11
|
export * from './declarations';
|
|
12
|
+
export * from './handlers';
|
|
13
|
+
export * from './rest';
|
|
21
14
|
|
|
22
|
-
const debug =
|
|
15
|
+
const debug = createDebug('@feathersjs/express');
|
|
23
16
|
|
|
24
17
|
export default function feathersExpress<S = any, C = any> (feathersApp?: FeathersApplication<S, C>, expressApp: Express = express()): Application<S, C> {
|
|
25
18
|
if (!feathersApp) {
|
|
@@ -30,10 +23,12 @@ export default function feathersExpress<S = any, C = any> (feathersApp?: Feather
|
|
|
30
23
|
throw new Error('@feathersjs/express requires a valid Feathers application instance');
|
|
31
24
|
}
|
|
32
25
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
26
|
+
const app = expressApp as any as Application<S, C>;
|
|
27
|
+
const { use: expressUse, listen: expressListen } = expressApp as any;
|
|
28
|
+
const { use: feathersUse, teardown: feathersTeardown } = feathersApp;
|
|
29
|
+
|
|
30
|
+
Object.assign(app, {
|
|
31
|
+
use (location: string & keyof S, ...rest: any[]) {
|
|
37
32
|
let service: any;
|
|
38
33
|
let options = {};
|
|
39
34
|
|
|
@@ -60,46 +55,63 @@ export default function feathersExpress<S = any, C = any> (feathersApp?: Feather
|
|
|
60
55
|
// Check for service (any object with at least one service method)
|
|
61
56
|
if (hasMethod(['handle', 'set']) || !hasMethod(defaultServiceMethods)) {
|
|
62
57
|
debug('Passing app.use call to Express app');
|
|
63
|
-
return
|
|
58
|
+
return expressUse.call(this, location, ...rest);
|
|
64
59
|
}
|
|
65
60
|
|
|
66
61
|
debug('Registering service with middleware', middleware);
|
|
67
62
|
// Since this is a service, call Feathers `.use`
|
|
68
|
-
|
|
63
|
+
feathersUse.call(this, location, service, {
|
|
69
64
|
...options,
|
|
70
|
-
middleware
|
|
65
|
+
express: middleware
|
|
71
66
|
});
|
|
72
67
|
|
|
73
68
|
return this;
|
|
74
69
|
},
|
|
75
70
|
|
|
76
71
|
async listen (...args: any[]) {
|
|
77
|
-
const server =
|
|
72
|
+
const server = expressListen.call(this, ...args);
|
|
78
73
|
|
|
74
|
+
this.server = server;
|
|
79
75
|
await this.setup(server);
|
|
80
76
|
debug('Feathers application listening');
|
|
81
77
|
|
|
82
78
|
return server;
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
async teardown (server?: any) {
|
|
82
|
+
return feathersTeardown.call(this, server).then(() =>
|
|
83
|
+
new Promise((resolve, reject) => this.server.close(e => e ? reject(e) : resolve(this)))
|
|
84
|
+
);
|
|
83
85
|
}
|
|
84
|
-
};
|
|
86
|
+
} as Application<S, C>);
|
|
85
87
|
|
|
86
|
-
const
|
|
88
|
+
const appDescriptors = {
|
|
89
|
+
...Object.getOwnPropertyDescriptors(Object.getPrototypeOf(app)),
|
|
90
|
+
...Object.getOwnPropertyDescriptors(app)
|
|
91
|
+
};
|
|
92
|
+
const newDescriptors = {
|
|
87
93
|
...Object.getOwnPropertyDescriptors(Object.getPrototypeOf(feathersApp)),
|
|
88
94
|
...Object.getOwnPropertyDescriptors(feathersApp)
|
|
89
95
|
};
|
|
90
96
|
|
|
91
97
|
// Copy all non-existing properties (including non-enumerables)
|
|
92
98
|
// that don't already exist on the Express app
|
|
93
|
-
Object.keys(
|
|
94
|
-
const
|
|
95
|
-
const
|
|
99
|
+
Object.keys(newDescriptors).forEach(prop => {
|
|
100
|
+
const appProp = appDescriptors[prop];
|
|
101
|
+
const newProp = newDescriptors[prop];
|
|
96
102
|
|
|
97
|
-
if (
|
|
98
|
-
Object.defineProperty(expressApp, prop,
|
|
103
|
+
if (appProp === undefined && newProp !== undefined) {
|
|
104
|
+
Object.defineProperty(expressApp, prop, newProp);
|
|
99
105
|
}
|
|
100
106
|
});
|
|
101
107
|
|
|
102
|
-
|
|
108
|
+
app.configure(routing() as any);
|
|
109
|
+
app.use((req, _res, next) => {
|
|
110
|
+
req.feathers = { ...req.feathers, provider: 'rest' };
|
|
111
|
+
return next();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return app;
|
|
103
115
|
}
|
|
104
116
|
|
|
105
117
|
if (typeof module !== 'undefined') {
|
package/src/rest.ts
CHANGED
|
@@ -1,160 +1,110 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Request, Response, RequestHandler, Router } from 'express';
|
|
2
2
|
import { MethodNotAllowed } from '@feathersjs/errors';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { createDebug } from '@feathersjs/commons';
|
|
4
|
+
import { http } from '@feathersjs/transport-commons';
|
|
5
|
+
import { createContext, defaultServiceMethods, getServiceOptions } from '@feathersjs/feathers';
|
|
6
6
|
|
|
7
|
-
import { parseAuthentication } from './authentication';
|
|
7
|
+
import { AuthenticationSettings, parseAuthentication } from './authentication';
|
|
8
|
+
import { Application } from './declarations';
|
|
8
9
|
|
|
9
|
-
const debug =
|
|
10
|
+
const debug = createDebug('@feathersjs/express/rest');
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export interface ServiceParams {
|
|
14
|
-
id: NullableId,
|
|
15
|
-
data: any,
|
|
16
|
-
params: Params
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export type ServiceCallback = (req: Request, res: Response, options: ServiceParams) => Promise<HookContext|any>;
|
|
20
|
-
|
|
21
|
-
export const statusCodes = {
|
|
22
|
-
created: 201,
|
|
23
|
-
noContent: 204,
|
|
24
|
-
methodNotAllowed: 405,
|
|
25
|
-
success: 200
|
|
12
|
+
const toHandler = (func: (req: Request, res: Response, next: () => void) => Promise<void>): RequestHandler => {
|
|
13
|
+
return (req, res, next) => func(req, res, next).catch(error => next(error));
|
|
26
14
|
};
|
|
27
15
|
|
|
28
|
-
|
|
29
|
-
req
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
headers: req.headers
|
|
33
|
-
};
|
|
34
|
-
next();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export const formatter = (_req: Request, res: Response, next: NextFunction) => {
|
|
38
|
-
if (res.data === undefined) {
|
|
39
|
-
return next();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
res.format({
|
|
43
|
-
'application/json' () {
|
|
44
|
-
res.json(res.data);
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
}
|
|
16
|
+
const serviceMiddleware = (): RequestHandler => {
|
|
17
|
+
return toHandler(async (req, res, next) => {
|
|
18
|
+
const { query, headers, path, body: data, method: httpMethod } = req;
|
|
19
|
+
const methodOverride = req.headers[http.METHOD_HEADER] as string | undefined;
|
|
48
20
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
21
|
+
const { service, params: { __id: id = null, ...route } = {} } = req.lookup!;
|
|
22
|
+
const method = http.getServiceMethod(httpMethod, id, methodOverride);
|
|
23
|
+
const { methods } = getServiceOptions(service);
|
|
53
24
|
|
|
54
|
-
|
|
55
|
-
? context.dispatch
|
|
56
|
-
: context.result;
|
|
57
|
-
}
|
|
25
|
+
debug(`Found service for path ${path}, attempting to run '${method}' service method`);
|
|
58
26
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
27
|
+
if (!methods.includes(method) || defaultServiceMethods.includes(methodOverride)) {
|
|
28
|
+
const error = new MethodNotAllowed(`Method \`${method}\` is not supported by this endpoint.`);
|
|
29
|
+
res.statusCode = error.code;
|
|
30
|
+
throw error;
|
|
63
31
|
}
|
|
64
32
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (!res.data) {
|
|
71
|
-
return statusCodes.noContent;
|
|
72
|
-
}
|
|
33
|
+
const createArguments = http.argumentsFor[method as 'get'] || http.argumentsFor.default;
|
|
34
|
+
const params = { query, headers, route, ...req.feathers };
|
|
35
|
+
const args = createArguments({ id, data, params });
|
|
36
|
+
const contextBase = createContext(service, method, { http: {} });
|
|
37
|
+
res.hook = contextBase;
|
|
73
38
|
|
|
74
|
-
|
|
75
|
-
|
|
39
|
+
const context = await (service as any)[method](...args, contextBase);
|
|
40
|
+
res.hook = context;
|
|
76
41
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
42
|
+
const response = http.getResponse(context);
|
|
43
|
+
res.statusCode = response.status;
|
|
44
|
+
res.set(response.headers);
|
|
45
|
+
res.data = response.body;
|
|
80
46
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const params = { query, route, ...req.feathers };
|
|
85
|
-
const context = await callback(req, res, { id, data, params });
|
|
47
|
+
return next();
|
|
48
|
+
});
|
|
49
|
+
};
|
|
86
50
|
|
|
87
|
-
|
|
88
|
-
|
|
51
|
+
const servicesMiddleware = (): RequestHandler => {
|
|
52
|
+
return toHandler(async (req, res, next) => {
|
|
53
|
+
const app = req.app as any as Application;
|
|
54
|
+
const lookup = app.lookup(req.path);
|
|
89
55
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
next(error);
|
|
56
|
+
if (!lookup) {
|
|
57
|
+
return next();
|
|
93
58
|
}
|
|
94
|
-
}
|
|
95
59
|
|
|
96
|
-
|
|
97
|
-
service: any, methodName: string, getArgs: (opts: ServiceParams) => any[], headerOverride?: string
|
|
98
|
-
) => serviceMiddleware(async (req, res, options) => {
|
|
99
|
-
const methodOverride = typeof headerOverride === 'string' && (req.headers[headerOverride] as string);
|
|
100
|
-
const method = methodOverride ? methodOverride : methodName
|
|
101
|
-
const { methods } = getServiceOptions(service);
|
|
60
|
+
req.lookup = lookup;
|
|
102
61
|
|
|
103
|
-
|
|
104
|
-
|
|
62
|
+
const options = getServiceOptions(lookup.service);
|
|
63
|
+
const middleware = options.express!.composed!;
|
|
105
64
|
|
|
106
|
-
|
|
65
|
+
return middleware(req, res, next);
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const formatter: RequestHandler = (_req, res, next) => {
|
|
70
|
+
if (res.data === undefined) {
|
|
71
|
+
return next();
|
|
107
72
|
}
|
|
108
73
|
|
|
109
|
-
|
|
110
|
-
|
|
74
|
+
res.format({
|
|
75
|
+
'application/json' () {
|
|
76
|
+
res.json(res.data);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
};
|
|
111
80
|
|
|
112
|
-
|
|
81
|
+
export type RestOptions = {
|
|
82
|
+
formatter?: RequestHandler;
|
|
83
|
+
authentication?: AuthenticationSettings;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const rest = (options?: RestOptions | RequestHandler) => {
|
|
87
|
+
options = typeof options === 'function' ? { formatter: options } : options || {};
|
|
113
88
|
|
|
114
|
-
|
|
115
|
-
|
|
89
|
+
const formatterMiddleware = options.formatter || formatter;
|
|
90
|
+
const authenticationOptions = options.authentication;
|
|
116
91
|
|
|
117
|
-
|
|
118
|
-
return function (this: any, app: any) {
|
|
92
|
+
return (app: Application) => {
|
|
119
93
|
if (typeof app.route !== 'function') {
|
|
120
94
|
throw new Error('@feathersjs/express/rest needs an Express compatible app.');
|
|
121
95
|
}
|
|
122
96
|
|
|
123
|
-
app.use(
|
|
124
|
-
app.use(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const baseUri = `/${path}`;
|
|
136
|
-
const find = serviceMethodHandler(service, 'find', ({ params }) => [ params ]);
|
|
137
|
-
const get = serviceMethodHandler(service, 'get', ({ id, params }) => [ id, params ]);
|
|
138
|
-
const create = serviceMethodHandler(service, 'create', ({ data, params }) => [ data, params ], METHOD_HEADER);
|
|
139
|
-
const update = serviceMethodHandler(service, 'update', ({ id, data, params }) => [ id, data, params ]);
|
|
140
|
-
const patch = serviceMethodHandler(service, 'patch', ({ id, data, params }) => [ id, data, params ]);
|
|
141
|
-
const remove = serviceMethodHandler(service, 'remove', ({ id, params }) => [ id, params ]);
|
|
142
|
-
|
|
143
|
-
debug(`Adding REST provider for service \`${path}\` at base route \`${baseUri}\``);
|
|
144
|
-
|
|
145
|
-
const idRoute = '/:__feathersId';
|
|
146
|
-
const serviceRouter = Router({ mergeParams: true })
|
|
147
|
-
.get('/', find)
|
|
148
|
-
.post('/', create)
|
|
149
|
-
.get(idRoute, get)
|
|
150
|
-
.put('/', update)
|
|
151
|
-
.put(idRoute, update)
|
|
152
|
-
.patch('/', patch)
|
|
153
|
-
.patch(idRoute, patch)
|
|
154
|
-
.delete('/', remove)
|
|
155
|
-
.delete(idRoute, remove);
|
|
156
|
-
|
|
157
|
-
app.use(baseUri, ...before, serviceRouter, ...after);
|
|
97
|
+
app.use(parseAuthentication(authenticationOptions));
|
|
98
|
+
app.use(servicesMiddleware());
|
|
99
|
+
|
|
100
|
+
app.mixins.push((_service, _path, options) => {
|
|
101
|
+
const { express: { before = [], after = [] } = {} } = options;
|
|
102
|
+
|
|
103
|
+
const middlewares = [].concat(before, serviceMiddleware(), after, formatterMiddleware);
|
|
104
|
+
const middleware = Router().use(middlewares);
|
|
105
|
+
|
|
106
|
+
options.express ||= {};
|
|
107
|
+
options.express.composed = middleware;
|
|
158
108
|
});
|
|
159
109
|
};
|
|
160
110
|
}
|