diff --git a/packages/rest/src/rest.application.ts b/packages/rest/src/rest.application.ts index 0445295cc961..261598e7200c 100644 --- a/packages/rest/src/rest.application.ts +++ b/packages/rest/src/rest.application.ts @@ -133,6 +133,11 @@ export class RestApplication extends Application implements HttpServerLike { this.restServer.basePath(path); } + controller(controllerCtor: ControllerClass, name?: string): Binding { + this.restServer.invalidateRoutingCache(); + return super.controller(controllerCtor, name); + } + /** * Register a new Controller-based route. * diff --git a/packages/rest/src/rest.server.ts b/packages/rest/src/rest.server.ts index bfb6f3d9409f..b5a19442e434 100644 --- a/packages/rest/src/rest.server.ts +++ b/packages/rest/src/rest.server.ts @@ -464,6 +464,11 @@ export class RestServer extends Context implements Server, HttpServerLike { response.redirect(302, fullUrl); } + // workaround for https://github.com/strongloop/loopback-next/issues/433 + invalidateRoutingCache(): void { + delete this._httpHandler; + } + /** * Register a controller class with this server. * @@ -482,6 +487,9 @@ export class RestServer extends Context implements Server, HttpServerLike { * */ controller(controllerCtor: ControllerClass): Binding { + this.invalidateRoutingCache(); + // FIXME(bajtos) This code is never used, a typical LB4 app is binding + // controller via `app.controller()` API return this.bind('controllers.' + controllerCtor.name).toClass( controllerCtor, ); @@ -564,6 +572,8 @@ export class RestServer extends Context implements Server, HttpServerLike { controllerFactory?: ControllerFactory, methodName?: string, ): Binding { + this.invalidateRoutingCache(); + if (typeof routeOrVerb === 'object') { const r = routeOrVerb; // Encode the path to escape special chars @@ -703,6 +713,9 @@ export class RestServer extends Context implements Server, HttpServerLike { let spec = this.getSync(RestBindings.API_SPEC); const defs = this.httpHandler.getApiDefinitions(); + // Apply shallow-clone to prevent modification of user-provided API_SPEC + spec = {...spec}; + // Apply deep clone to prevent getApiSpec() callers from // accidentally modifying our internal routing data spec.paths = cloneDeep(this.httpHandler.describeApiPaths());