feat(events-backend,events-node): improve parser interface

Signed-off-by: Rogerio Angeliski <angeliski@hotmail.com>
This commit is contained in:
Rogerio Angeliski
2025-02-26 20:18:14 -03:00
parent 144661b05f
commit cf75bca4f3
7 changed files with 58 additions and 7 deletions
@@ -209,7 +209,7 @@ describe('HttpPostIngressEventPublisher', () => {
expect.objectContaining({
error: {
message:
'Unsupported media type: text/plain. You need to provide a custom body parser for this media type using events extension.',
'Unsupported media type: text/plain. You need to provide a custom body parser for this media type using the EventsExtensionPoint.',
name: 'UnsupportedMediaTypeError',
statusCode: 415,
},
@@ -259,6 +259,47 @@ describe('HttpPostIngressEventPublisher', () => {
expect(response.status).toBe(202);
});
it('with a invalid media type', async () => {
const config = new ConfigReader({
events: {
http: {
topics: ['testA'],
},
},
});
const router = Router();
const app = express().use(router);
const events = new TestEventsService();
const publisher = HttpPostIngressEventPublisher.fromConfig({
config,
events,
logger,
});
publisher.bind(router);
router.use(middleware.error());
const response = await request(app)
.post('/http/testA')
.type('not-valid-content/plain')
.timeout(1000)
.send('Textual information');
expect(response.status).toBe(415);
expect(response.body).toEqual(
expect.objectContaining({
error: {
message:
'Unsupported media type: not-valid-content/plain. You need to provide a custom body parser for this media type using the EventsExtensionPoint.',
name: 'UnsupportedMediaTypeError',
statusCode: 415,
},
request: { method: 'POST', url: '/http/testA' },
response: { statusCode: 415 },
}),
);
});
it('with a custom application/json body parser implementation', async () => {
const config = new ConfigReader({
events: {
@@ -273,7 +314,11 @@ describe('HttpPostIngressEventPublisher', () => {
const events = new TestEventsService();
const customParse = jest.fn();
const bodyParser: HttpBodyParser = async (req, _topic) => {
const bodyParser: HttpBodyParser = async (
req,
_parsedMediaType,
_topic,
) => {
customParse();
return {
bodyParsed: JSON.parse(req.body.toString('utf-8')),
@@ -103,7 +103,7 @@ export class HttpPostIngressEventPublisher {
router.post(path, async (request, response) => {
const requestContentType = contentType.parse(request);
const bodyParser = this.bodyParsers[requestContentType.type];
const bodyParser = this.bodyParsers[requestContentType.type ?? ''];
if (!bodyParser) {
throw new UnsupportedMediaTypeError(requestContentType.type);
@@ -111,6 +111,7 @@ export class HttpPostIngressEventPublisher {
const { bodyParsed, bodyBuffer, encoding } = await bodyParser(
request,
requestContentType,
topic,
);
@@ -14,11 +14,11 @@
* limitations under the License.
*/
import { HttpBodyParser } from '@backstage/plugin-events-node';
import contentType from 'content-type';
import { UnsupportedCharsetError } from '../errors';
export const HttpApplicationJsonBodyParser: HttpBodyParser = async (
request,
parsedMediaType,
topic,
) => {
const requestBody = request.body;
@@ -29,16 +29,15 @@ export const HttpApplicationJsonBodyParser: HttpBodyParser = async (
}
const bodyBuffer: Buffer = requestBody;
const parsedContentType = contentType.parse(request);
const encoding = parsedContentType.parameters.charset ?? 'utf-8';
const encoding = parsedMediaType.parameters.charset ?? 'utf-8';
if (!Buffer.isEncoding(encoding)) {
throw new UnsupportedCharsetError(encoding);
}
const bodyString = bodyBuffer.toString(encoding);
const bodyParsed =
parsedContentType.type === 'application/json'
parsedMediaType.type === 'application/json'
? JSON.parse(bodyString)
: bodyString;
return { bodyParsed, bodyBuffer, encoding };
+1
View File
@@ -56,6 +56,7 @@
"@backstage/errors": "workspace:^",
"@backstage/types": "workspace:^",
"@types/express": "^4.17.6",
"content-type": "^1.0.5",
"cross-fetch": "^4.0.0",
"express": "^4.17.1",
"uri-template": "^2.0.0"
+2
View File
@@ -9,6 +9,7 @@ import { AuthService } from '@backstage/backend-plugin-api';
import { DiscoveryService } from '@backstage/backend-plugin-api';
import { LifecycleService } from '@backstage/backend-plugin-api';
import { LoggerService } from '@backstage/backend-plugin-api';
import { ParsedMediaType } from 'content-type';
import { Request as Request_2 } from 'express';
import { RootConfigService } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
@@ -122,6 +123,7 @@ export type HttpBodyParsed = {
// @public (undocumented)
export type HttpBodyParser = (
request: Request_2,
parsedMediaType: ParsedMediaType,
topic: string,
) => Promise<HttpBodyParsed>;
@@ -15,6 +15,7 @@
*/
import { Request } from 'express';
import { ParsedMediaType } from 'content-type';
/**
* @public
*/
@@ -29,5 +30,6 @@ export type HttpBodyParsed = {
*/
export type HttpBodyParser = (
request: Request,
parsedMediaType: ParsedMediaType,
topic: string,
) => Promise<HttpBodyParsed>;
+1
View File
@@ -6728,6 +6728,7 @@ __metadata:
"@backstage/errors": "workspace:^"
"@backstage/types": "workspace:^"
"@types/express": ^4.17.6
content-type: ^1.0.5
cross-fetch: ^4.0.0
express: ^4.17.1
msw: ^1.0.0