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