diff --git a/packages/rest/src/__tests__/integration/request-context.integration.ts b/packages/rest/src/__tests__/integration/request-context.integration.ts index 8ca16beb9a07..57e082455f43 100644 --- a/packages/rest/src/__tests__/integration/request-context.integration.ts +++ b/packages/rest/src/__tests__/integration/request-context.integration.ts @@ -88,6 +88,20 @@ describe('RequestContext', () => { expect(observedCtx.basePath).to.equal('/api/v1'); }); + + it('honors basePath from server config', async () => { + await givenRunningAppWithClient({basePath: '/api'}); + await client.get('/api/products').expect(200); + expect(observedCtx.basePath).to.equal('/api'); + }); + + it('honors basePath set via basePath() method', async () => { + await givenRunningAppWithClient({}, a => { + a.restServer.basePath('/api'); + }); + await client.get('/api/products').expect(200); + expect(observedCtx.basePath).to.equal('/api'); + }); }); describe('requestedBaseUrl', () => { @@ -142,12 +156,16 @@ async function teardown() { if (app) await app.stop(); } -async function givenRunningAppWithClient(restOptions?: RestServerConfig) { +async function givenRunningAppWithClient( + restOptions?: RestServerConfig, + setupFn: (app: RestApplication) => void = () => {}, +) { const options: ApplicationConfig = { rest: givenHttpServerConfig(restOptions), }; app = new RestApplication(options); app.handler(contextObservingHandler); + setupFn(app); await app.start(); client = createRestAppClient(app); } diff --git a/packages/rest/src/__tests__/integration/rest.server.integration.ts b/packages/rest/src/__tests__/integration/rest.server.integration.ts index 330a5122ca1a..05b04d2362f8 100644 --- a/packages/rest/src/__tests__/integration/rest.server.integration.ts +++ b/packages/rest/src/__tests__/integration/rest.server.integration.ts @@ -854,6 +854,14 @@ paths: expect(response.body.servers).to.containEql({url: '/api'}); }); + it('controls server urls even when set via server.basePath() API', async () => { + server.basePath('/v2'); + const response = await createClientForHandler(server.requestHandler).get( + '/openapi.json', + ); + expect(response.body.servers).to.containEql({url: '/v2'}); + }); + it('controls redirect locations', async () => { server.controller(DummyController); server.redirect('/page/html', '/html'); diff --git a/packages/rest/src/request-context.ts b/packages/rest/src/request-context.ts index 08e8d808616c..e31cbd888148 100644 --- a/packages/rest/src/request-context.ts +++ b/packages/rest/src/request-context.ts @@ -38,7 +38,12 @@ export class RequestContext extends Context implements HandlerContext { const request = this.request; let basePath = this.serverConfig.basePath || ''; if (request.baseUrl && request.baseUrl !== '/') { - basePath = request.baseUrl + basePath; + if (!basePath || request.baseUrl.endsWith(basePath)) { + // Express has already applied basePath to baseUrl + basePath = request.baseUrl; + } else { + basePath = request.baseUrl + basePath; + } } return basePath; } diff --git a/packages/rest/src/rest.server.ts b/packages/rest/src/rest.server.ts index 6fedc63ee5f1..68484fd3b73c 100644 --- a/packages/rest/src/rest.server.ts +++ b/packages/rest/src/rest.server.ts @@ -776,6 +776,7 @@ export class RestServer extends Context implements Server, HttpServerLike { path = path.replace(/(^\/)|(\/$)/, ''); if (path) path = '/' + path; this._basePath = path; + this.config.basePath = path; } /**