Add more control on http trigger (#21216)
add "new Response" utils to define response code or content type of http route triggered logic function responses follow up of https://github.com/twentyhq/twenty/pull/21214 --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+49
@@ -0,0 +1,49 @@
|
||||
import { LOGIC_FUNCTION_HTTP_RESPONSE_MARKER } from 'twenty-shared/types';
|
||||
|
||||
import { buildRouteTriggerResponse } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/route-trigger.service';
|
||||
|
||||
describe('buildRouteTriggerResponse', () => {
|
||||
it('wraps a plain body with status 200 and no headers', () => {
|
||||
expect(buildRouteTriggerResponse({ message: 'hi' })).toEqual({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
body: { message: 'hi' },
|
||||
});
|
||||
});
|
||||
|
||||
it('passes through null/undefined as a 200 with that body', () => {
|
||||
expect(buildRouteTriggerResponse(null)).toEqual({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
body: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('reads status, headers and body from a wrapped response', () => {
|
||||
const data = {
|
||||
[LOGIC_FUNCTION_HTTP_RESPONSE_MARKER]: true,
|
||||
body: '<h1>Hi</h1>',
|
||||
status: 201,
|
||||
headers: { 'Content-Type': 'text/html' },
|
||||
};
|
||||
|
||||
expect(buildRouteTriggerResponse(data)).toEqual({
|
||||
statusCode: 201,
|
||||
headers: { 'Content-Type': 'text/html' },
|
||||
body: '<h1>Hi</h1>',
|
||||
});
|
||||
});
|
||||
|
||||
it('defaults a wrapped response without status/headers to 200 and {}', () => {
|
||||
const data = {
|
||||
[LOGIC_FUNCTION_HTTP_RESPONSE_MARKER]: true,
|
||||
body: { ok: true },
|
||||
};
|
||||
|
||||
expect(buildRouteTriggerResponse(data)).toEqual({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
body: { ok: true },
|
||||
});
|
||||
});
|
||||
});
|
||||
+23
-3
@@ -5,7 +5,7 @@ import { Request } from 'express';
|
||||
import { match } from 'path-to-regexp';
|
||||
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
|
||||
import { IsNull, Not, Repository } from 'typeorm';
|
||||
import { HTTPMethod } from 'twenty-shared/types';
|
||||
import { HTTPMethod, isLogicFunctionHttpResponse } from 'twenty-shared/types';
|
||||
|
||||
import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service';
|
||||
import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service';
|
||||
@@ -26,6 +26,26 @@ import {
|
||||
} from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service';
|
||||
import { CustomException } from 'src/utils/custom-exception';
|
||||
|
||||
export type RouteTriggerResponse = {
|
||||
statusCode: number;
|
||||
headers: Record<string, string>;
|
||||
body: unknown;
|
||||
};
|
||||
|
||||
export const buildRouteTriggerResponse = (
|
||||
data: unknown,
|
||||
): RouteTriggerResponse => {
|
||||
if (isLogicFunctionHttpResponse(data)) {
|
||||
return {
|
||||
statusCode: data.status ?? 200,
|
||||
headers: data.headers ?? {},
|
||||
body: data.body,
|
||||
};
|
||||
}
|
||||
|
||||
return { statusCode: 200, headers: {}, body: data };
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class RouteTriggerService {
|
||||
private readonly logger = new Logger(RouteTriggerService.name);
|
||||
@@ -223,7 +243,7 @@ export class RouteTriggerService {
|
||||
}
|
||||
|
||||
if (!isDefined(result)) {
|
||||
return result;
|
||||
return buildRouteTriggerResponse(result);
|
||||
}
|
||||
|
||||
if (result.error) {
|
||||
@@ -233,6 +253,6 @@ export class RouteTriggerService {
|
||||
);
|
||||
}
|
||||
|
||||
return result.data;
|
||||
return buildRouteTriggerResponse(result.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user