fix: migrate webhook and API key REST endpoints to core schema (#13318)

## Problem
After migrating webhooks and API keys from workspace to core level, REST
API endpoints were still creating entities in workspace schema
(`workspace_*`) instead of core schema, causing webhooks to not fire.

## Solution
- Added dedicated REST controllers for webhooks (`/rest/webhooks`) and
API keys (`/rest/apiKeys`)
- Updated dynamic controller to block workspace-gated entities from
being processed
- Fixed OpenAPI documentation to exclude these endpoints from playground
- Ensured return formats match GraphQL resolvers exactly

## Testing
 All endpoints tested with provided auth token - webhooks and API keys
now correctly stored in `core` schema
This commit is contained in:
nitin
2025-07-23 18:41:53 +05:30
committed by GitHub
parent 05a09d7a73
commit 0e561e4ef4
17 changed files with 302 additions and 68 deletions

View File

@ -17,10 +17,9 @@ import {
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
import { getResolverName } from 'src/engine/utils/get-resolver-name.util';
import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects';
import { isGatedAndNotEnabled } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-gate-and-not-enabled.util';
import { shouldExcludeFromWorkspaceApi } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/should-exclude-from-workspace-api.util';
import { CreateManyResolverFactory } from './factories/create-many-resolver.factory';
import { CreateOneResolverFactory } from './factories/create-one-resolver.factory';
@ -100,27 +99,14 @@ export class WorkspaceResolverFactory {
for (const objectMetadata of Object.values(objectMetadataMaps.byId).filter(
isDefined,
)) {
const workspaceEntity = standardObjectMetadataDefinitions.find(
(entity) => {
const entityMetadata = metadataArgsStorage.filterEntities(entity);
return entityMetadata?.standardId === objectMetadata.standardId;
},
);
if (workspaceEntity) {
const entityMetadata =
metadataArgsStorage.filterEntities(workspaceEntity);
if (
isGatedAndNotEnabled(
entityMetadata?.gate,
workspaceFeatureFlagsMap,
'graphql',
)
) {
continue;
}
if (
shouldExcludeFromWorkspaceApi(
objectMetadata,
standardObjectMetadataDefinitions,
workspaceFeatureFlagsMap,
)
) {
continue;
}
// Generate query resolvers

View File

@ -21,10 +21,9 @@ import {
WorkspaceMetadataCacheExceptionCode,
} from 'src/engine/metadata-modules/workspace-metadata-cache/exceptions/workspace-metadata-cache.exception';
import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/workspace-metadata-cache/services/workspace-metadata-cache.service';
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
import { WorkspaceCacheStorageService } from 'src/engine/workspace-cache-storage/workspace-cache-storage.service';
import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects';
import { isGatedAndNotEnabled } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-gate-and-not-enabled.util';
import { shouldExcludeFromWorkspaceApi } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/should-exclude-from-workspace-api.util';
@Injectable()
export class WorkspaceSchemaFactory {
@ -86,27 +85,10 @@ export class WorkspaceSchemaFactory {
indexes: objectMetadataItem.indexMetadatas,
}))
.filter((objectMetadata) => {
// Find the corresponding workspace entity for this object metadata
const workspaceEntity = standardObjectMetadataDefinitions.find(
(entity) => {
const entityMetadata = metadataArgsStorage.filterEntities(entity);
return entityMetadata?.standardId === objectMetadata.standardId;
},
);
if (!workspaceEntity) {
return true; // Include non-workspace entities (custom objects, etc.)
}
const entityMetadata =
metadataArgsStorage.filterEntities(workspaceEntity);
// Filter out entities that are GraphQL-gated and not enabled
return !isGatedAndNotEnabled(
entityMetadata?.gate,
return !shouldExcludeFromWorkspaceApi(
objectMetadata,
standardObjectMetadataDefinitions,
workspaceFeatureFlagsMap,
'graphql',
);
});