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'
|
5 | import cors from 'cors'
|
6 | import compression from 'compression'
|
7 |
|
8 | import { rest, RestOptions, formatter } from './rest'
|
9 | import { errorHandler, notFound, ErrorHandlerOptions } from './handlers'
|
10 | import { Application, ExpressOverrides } from './declarations'
|
11 | import { AuthenticationSettings, authenticate, parseAuthentication } from './authentication'
|
12 | import { default as original, static as serveStatic, json, raw, text, urlencoded, query } from 'express'
|
13 |
|
14 | export {
|
15 | original,
|
16 | serveStatic,
|
17 | serveStatic as static,
|
18 | json,
|
19 | raw,
|
20 | text,
|
21 | urlencoded,
|
22 | query,
|
23 | rest,
|
24 | RestOptions,
|
25 | formatter,
|
26 | errorHandler,
|
27 | notFound,
|
28 | Application,
|
29 | ErrorHandlerOptions,
|
30 | ExpressOverrides,
|
31 | AuthenticationSettings,
|
32 | parseAuthentication,
|
33 | authenticate,
|
34 | cors,
|
35 | compression
|
36 | }
|
37 |
|
38 | const debug = createDebug('@feathersjs/express')
|
39 |
|
40 | export default function feathersExpress<S = any, C = any>(
|
41 | feathersApp?: FeathersApplication<S, C>,
|
42 | expressApp: Express = express()
|
43 | ): Application<S, C> {
|
44 | if (!feathersApp) {
|
45 | return expressApp as any
|
46 | }
|
47 |
|
48 | if (typeof feathersApp.setup !== 'function') {
|
49 | throw new Error('@feathersjs/express requires a valid Feathers application instance')
|
50 | }
|
51 |
|
52 | const app = expressApp as any as Application<S, C>
|
53 | const { use: expressUse, listen: expressListen } = expressApp as any
|
54 | const { use: feathersUse, teardown: feathersTeardown } = feathersApp
|
55 |
|
56 | Object.assign(app, {
|
57 | use(location: string & keyof S, ...rest: any[]) {
|
58 | let service: any
|
59 | let options = {}
|
60 |
|
61 | const middleware = rest.reduce(
|
62 | function (middleware, arg) {
|
63 | if (typeof arg === 'function' || Array.isArray(arg)) {
|
64 | middleware[service ? 'after' : 'before'].push(arg)
|
65 | } else if (!service) {
|
66 | service = arg
|
67 | } else if (arg.methods || arg.events || arg.express || arg.koa) {
|
68 | options = arg
|
69 | } else {
|
70 | throw new Error('Invalid options passed to app.use')
|
71 | }
|
72 | return middleware
|
73 | },
|
74 | {
|
75 | before: [],
|
76 | after: []
|
77 | }
|
78 | )
|
79 |
|
80 | const hasMethod = (methods: string[]) =>
|
81 | methods.some((name) => service && typeof service[name] === 'function')
|
82 |
|
83 |
|
84 | if (hasMethod(['handle', 'set']) || !hasMethod(defaultServiceMethods)) {
|
85 | debug('Passing app.use call to Express app')
|
86 | return expressUse.call(this, location, ...rest)
|
87 | }
|
88 |
|
89 | debug('Registering service with middleware', middleware)
|
90 |
|
91 | feathersUse.call(this, location, service, {
|
92 | express: middleware,
|
93 | ...options
|
94 | })
|
95 |
|
96 | return this
|
97 | },
|
98 |
|
99 | async listen(...args: any[]) {
|
100 | const server = expressListen.call(this, ...args)
|
101 |
|
102 | this.server = server
|
103 | await this.setup(server)
|
104 | debug('Feathers application listening')
|
105 |
|
106 | return server
|
107 | }
|
108 | } as Application<S, C>)
|
109 |
|
110 | const appDescriptors = {
|
111 | ...Object.getOwnPropertyDescriptors(Object.getPrototypeOf(app)),
|
112 | ...Object.getOwnPropertyDescriptors(app)
|
113 | }
|
114 | const newDescriptors = {
|
115 | ...Object.getOwnPropertyDescriptors(Object.getPrototypeOf(feathersApp)),
|
116 | ...Object.getOwnPropertyDescriptors(feathersApp)
|
117 | }
|
118 |
|
119 |
|
120 |
|
121 | Object.keys(newDescriptors).forEach((prop) => {
|
122 | const appProp = appDescriptors[prop]
|
123 | const newProp = newDescriptors[prop]
|
124 |
|
125 | if (appProp === undefined && newProp !== undefined) {
|
126 | Object.defineProperty(expressApp, prop, newProp)
|
127 | }
|
128 | })
|
129 |
|
130 |
|
131 | app.setup = feathersApp.setup as any
|
132 | app.teardown = async function teardown(server?: any) {
|
133 | return feathersTeardown.call(this, server).then(
|
134 | () =>
|
135 | new Promise((resolve, reject) => {
|
136 | if (this.server) {
|
137 | this.server.close((e) => (e ? reject(e) : resolve(this)))
|
138 | } else {
|
139 | resolve(this)
|
140 | }
|
141 | })
|
142 | )
|
143 | }
|
144 |
|
145 | app.configure(routing() as any)
|
146 | app.use((req, _res, next) => {
|
147 | req.feathers = { ...req.feathers, provider: 'rest' }
|
148 | return next()
|
149 | })
|
150 |
|
151 | return app
|
152 | }
|
153 |
|
154 | if (typeof module !== 'undefined') {
|
155 | module.exports = Object.assign(feathersExpress, module.exports)
|
156 | }
|