diff --git a/.changeset/kind-pens-deliver.md b/.changeset/kind-pens-deliver.md new file mode 100644 index 0000000000..e4937cb396 --- /dev/null +++ b/.changeset/kind-pens-deliver.md @@ -0,0 +1,10 @@ +--- +'@backstage/techdocs-common': patch +'@backstage/plugin-auth-backend': patch +'@backstage/plugin-kafka-backend': patch +'@backstage/plugin-kubernetes-backend': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-techdocs-backend': patch +--- + +remove usage of res.send() for res.json() and res.end() to ensure content types are more consistently application/json on backend responses and error cases diff --git a/packages/techdocs-common/src/stages/publish/awsS3.ts b/packages/techdocs-common/src/stages/publish/awsS3.ts index 90b70ba747..a1abd5899d 100644 --- a/packages/techdocs-common/src/stages/publish/awsS3.ts +++ b/packages/techdocs-common/src/stages/publish/awsS3.ts @@ -257,7 +257,7 @@ export class AwsS3Publish implements PublisherBase { res.send(await streamToBuffer(stream)); } catch (err) { this.logger.warn(err.message); - res.status(404).send(err.message); + res.status(404).json(err.message); } }; } diff --git a/packages/techdocs-common/src/stages/publish/azureBlobStorage.ts b/packages/techdocs-common/src/stages/publish/azureBlobStorage.ts index 0d2e9871bf..2136ee2bc2 100644 --- a/packages/techdocs-common/src/stages/publish/azureBlobStorage.ts +++ b/packages/techdocs-common/src/stages/publish/azureBlobStorage.ts @@ -257,7 +257,7 @@ export class AzureBlobStoragePublish implements PublisherBase { }); } catch (e) { this.logger.error(e.message); - res.status(404).send(e.message); + res.status(404).json(e.message); } }; } diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts index d2b31213f2..38e21f04e8 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts @@ -173,6 +173,7 @@ describe('OAuthAdapter', () => { const mockResponse = ({ cookie: jest.fn().mockReturnThis(), send: jest.fn().mockReturnThis(), + status: jest.fn().mockReturnThis(), } as unknown) as express.Response; await oauthProvider.logout(mockRequest, mockResponse); @@ -200,12 +201,13 @@ describe('OAuthAdapter', () => { } as unknown) as express.Request; const mockResponse = ({ - send: jest.fn().mockReturnThis(), + json: jest.fn().mockReturnThis(), + status: jest.fn().mockReturnThis(), } as unknown) as express.Response; await oauthProvider.refresh(mockRequest, mockResponse); - expect(mockResponse.send).toHaveBeenCalledTimes(1); - expect(mockResponse.send).toHaveBeenCalledWith({ + expect(mockResponse.json).toHaveBeenCalledTimes(1); + expect(mockResponse.json).toHaveBeenCalledWith({ ...mockResponseData, backstageIdentity: { id: mockResponseData.backstageIdentity.id, @@ -230,6 +232,7 @@ describe('OAuthAdapter', () => { const mockResponse = ({ send: jest.fn().mockReturnThis(), + status: jest.fn().mockReturnThis(), } as unknown) as express.Response; await oauthProvider.refresh(mockRequest, mockResponse); diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts index 62cb8e444d..d6454fd807 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts @@ -155,7 +155,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { // remove refresh token cookie before logout this.removeRefreshTokenCookie(res); } - res.send('logout!'); + res.status(200).send('logout!'); } async refresh(req: express.Request, res: express.Response): Promise { @@ -165,9 +165,11 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { } if (!this.handlers.refresh || this.options.disableRefresh) { - res.send( - `Refresh token not supported for provider: ${this.options.providerId}`, - ); + res + .status(400) + .send( + `Refresh token not supported for provider: ${this.options.providerId}`, + ); return; } @@ -198,7 +200,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { this.setRefreshTokenCookie(res, response.providerInfo.refreshToken); } - res.send(response); + res.status(200).json(response); } catch (error) { res.status(401).send(`${error.message}`); } diff --git a/plugins/auth-backend/src/providers/aws-alb/provider.test.ts b/plugins/auth-backend/src/providers/aws-alb/provider.test.ts index d05b6bbfaf..4a2b0f017c 100644 --- a/plugins/auth-backend/src/providers/aws-alb/provider.test.ts +++ b/plugins/auth-backend/src/providers/aws-alb/provider.test.ts @@ -77,7 +77,6 @@ describe('AwsALBAuthProvider', () => { getEntityByName: jest.fn(), }; - const mockResponseSend = jest.fn(); const mockRequest = ({ header: jest.fn(() => { return 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZvbyIsImlzcyI6ImZvbyJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.T2BNS4G-6RoiFnXc8Q8TiwdWzTpNitY8jcsGM3N3-Yo'; @@ -89,8 +88,10 @@ describe('AwsALBAuthProvider', () => { }), } as unknown) as express.Request; const mockResponse = ({ + end: jest.fn(), header: () => jest.fn(), - send: mockResponseSend, + json: jest.fn().mockReturnThis(), + status: jest.fn(), } as unknown) as express.Response; describe('should transform to type OAuthResponse', () => { @@ -107,7 +108,7 @@ describe('AwsALBAuthProvider', () => { await provider.refresh(mockRequest, mockResponse); - expect(mockResponseSend.mock.calls[0][0]).toEqual({ + expect(mockResponse.json).toHaveBeenCalledWith({ backstageIdentity: { id: 'foo', idToken: '', @@ -129,7 +130,7 @@ describe('AwsALBAuthProvider', () => { await provider.refresh(mockRequestWithoutJwt, mockResponse); - expect(mockResponseSend.mock.calls[0][0]).toEqual(401); + expect(mockResponse.status).toHaveBeenCalledWith(401); }); it('JWT is invalid', async () => { @@ -145,7 +146,7 @@ describe('AwsALBAuthProvider', () => { await provider.refresh(mockRequest, mockResponse); - expect(mockResponseSend.mock.calls[0][0]).toEqual(401); + expect(mockResponse.status).toHaveBeenCalledWith(401); }); it('issuer is invalid', async () => { @@ -158,8 +159,7 @@ describe('AwsALBAuthProvider', () => { jwtMock.verify.mockReturnValueOnce({}); await provider.refresh(mockRequest, mockResponse); - - expect(mockResponseSend.mock.calls[0][0]).toEqual(401); + expect(mockResponse.status).toHaveBeenCalledWith(401); }); it('identity resolution callback rejects', async () => { @@ -173,7 +173,8 @@ describe('AwsALBAuthProvider', () => { await provider.refresh(mockRequest, mockResponse); - expect(mockResponseSend.mock.calls[0][0]).toEqual(401); + expect(mockResponse.status).toHaveBeenCalledWith(401); + expect(mockResponse.end).toHaveBeenCalledTimes(1); }); }); }); diff --git a/plugins/auth-backend/src/providers/aws-alb/provider.ts b/plugins/auth-backend/src/providers/aws-alb/provider.ts index 27baaded0f..5b0bb8a33f 100644 --- a/plugins/auth-backend/src/providers/aws-alb/provider.ts +++ b/plugins/auth-backend/src/providers/aws-alb/provider.ts @@ -78,13 +78,15 @@ export class AwsAlbAuthProvider implements AuthProviderRouteHandlers { payload, this.catalogClient, ); - res.send(resolvedEntity); + res.json(resolvedEntity); } catch (e) { this.logger.error('exception occurred during JWT processing', e); - res.send(401); + res.status(401); + res.end(); } } else { - res.send(401); + res.status(401); + res.end(); } } diff --git a/plugins/kafka-backend/src/service/router.ts b/plugins/kafka-backend/src/service/router.ts index 465347ed8f..3360bbb1de 100644 --- a/plugins/kafka-backend/src/service/router.ts +++ b/plugins/kafka-backend/src/service/router.ts @@ -68,7 +68,7 @@ export const makeRouter = ( })); }), ); - res.send({ consumerId, offsets: groupWithTopicOffsets.flat() }); + res.json({ consumerId, offsets: groupWithTopicOffsets.flat() }); }); return router; diff --git a/plugins/kubernetes-backend/src/service/router.ts b/plugins/kubernetes-backend/src/service/router.ts index 32b6dfb832..333f48a623 100644 --- a/plugins/kubernetes-backend/src/service/router.ts +++ b/plugins/kubernetes-backend/src/service/router.ts @@ -70,12 +70,12 @@ export const makeRouter = ( const response = await kubernetesFanOutHandler.getKubernetesObjectsByEntity( requestBody, ); - res.send(response); + res.json(response); } catch (e) { logger.error( `action=retrieveObjectsByServiceId service=${serviceId}, error=${e}`, ); - res.status(500).send({ error: e.message }); + res.status(500).json({ error: e.message }); } }); diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 65b9039e27..1645cb928d 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -132,11 +132,11 @@ export async function createRouter( const job = jobProcessor.get(params.jobId); if (!job) { - res.status(404).send({ error: 'job not found' }); + res.status(404).json({ error: 'job not found' }); return; } - res.send({ + res.json({ id: job.id, metadata: { ...job.context, diff --git a/plugins/techdocs-backend/src/service/router.ts b/plugins/techdocs-backend/src/service/router.ts index d300400c70..8951bc4664 100644 --- a/plugins/techdocs-backend/src/service/router.ts +++ b/plugins/techdocs-backend/src/service/router.ts @@ -63,7 +63,7 @@ export async function createRouter({ entityName, ); - res.send(techdocsMetadata); + res.json(techdocsMetadata); } catch (err) { logger.error( `Unable to get metadata for ${entityName.namespace}/${entityName.name} with error ${err}`, @@ -93,7 +93,7 @@ export async function createRouter({ ).json()) as Entity; const locationMetadata = getLocationForEntity(entity); - res.send({ ...entity, locationMetadata }); + res.json({ ...entity, locationMetadata }); } catch (err) { logger.info( `Unable to get metadata for ${kind}/${namespace}/${name} with error ${err}`,