Skip to content

Commit d6cabe7

Browse files
Convert legacy GCF events to CloudEvents (#285)
This commit adds express middleware to convert legacy GCF requests to the equivalent CloudEvent requests. This enables developers to leverage cloud events in functions that consume events from GCP products that don't yet produce CloudEvents.
1 parent 0dc3fd7 commit d6cabe7

File tree

9 files changed

+697
-71
lines changed

9 files changed

+697
-71
lines changed

.github/workflows/conformance.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,6 @@ jobs:
5454
with:
5555
functionType: 'cloudevent'
5656
useBuildpacks: false
57-
validateMapping: false
57+
validateMapping: true
5858
workingDirectory: 'test/conformance'
5959
cmd: "'npm start -- --target=writeCloudEvent --signature-type=cloudevent'"

src/cloudevents.ts

+15
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,21 @@
1515
import * as express from 'express';
1616
import {CloudEventsContext} from './functions';
1717

18+
/**
19+
* Custom exception class to represent errors durring event conversions.
20+
*/
21+
export class EventConversionError extends Error {}
22+
23+
// CloudEvent service names.
24+
export const CE_SERVICE = {
25+
FIREBASE_AUTH: 'firebaseauth.googleapis.com',
26+
FIREBASE_DB: 'firebasedatabase.googleapis.com',
27+
FIREBASE: 'firebase.googleapis.com',
28+
FIRESTORE: 'firestore.googleapis.com',
29+
PUBSUB: 'pubsub.googleapis.com',
30+
STORAGE: 'storage.googleapis.com',
31+
};
32+
1833
/**
1934
* Checks whether the incoming request is a CloudEvents event in binary content
2035
* mode. This is verified by checking the presence of required headers.

src/functions.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export type HandlerFunction =
4444
* A legacy event.
4545
*/
4646
export interface LegacyEvent {
47-
data: object;
47+
data: {[key: string]: any};
4848
context: CloudFunctionsContext;
4949
}
5050

@@ -75,7 +75,7 @@ export interface CloudFunctionsContext {
7575
/**
7676
* The resource that emitted the event.
7777
*/
78-
resource?: string | object;
78+
resource?: string | {[key: string]: string};
7979
}
8080

8181
/**

src/middelware/ce_to_legacy_event.ts

+43-50
Original file line numberDiff line numberDiff line change
@@ -12,47 +12,45 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414
import {Request, Response, NextFunction} from 'express';
15-
import {isBinaryCloudEvent, getBinaryCloudEventContext} from '../cloudevents';
15+
import {
16+
CE_SERVICE,
17+
isBinaryCloudEvent,
18+
getBinaryCloudEventContext,
19+
EventConversionError,
20+
} from '../cloudevents';
1621

17-
const CE_TO_BACKGROUND_TYPE = new Map(
18-
Object.entries({
19-
'google.cloud.pubsub.topic.v1.messagePublished':
20-
'google.pubsub.topic.publish',
21-
'google.cloud.storage.object.v1.finalized':
22-
'google.storage.object.finalize',
23-
'google.cloud.storage.object.v1.deleted': 'google.storage.object.delete',
24-
'google.cloud.storage.object.v1.archived': 'google.storage.object.archive',
25-
'google.cloud.storage.object.v1.metadataUpdated':
26-
'google.storage.object.metadataUpdate',
27-
'google.cloud.firestore.document.v1.written':
28-
'providers/cloud.firestore/eventTypes/document.write',
29-
'google.cloud.firestore.document.v1.created':
30-
'providers/cloud.firestore/eventTypes/document.create',
31-
'google.cloud.firestore.document.v1.updated':
32-
'providers/cloud.firestore/eventTypes/document.update',
33-
'google.cloud.firestore.document.v1.deleted':
34-
'providers/cloud.firestore/eventTypes/document.delete',
35-
'google.firebase.auth.user.v1.created':
36-
'providers/firebase.auth/eventTypes/user.create',
37-
'google.firebase.auth.user.v1.deleted':
38-
'providers/firebase.auth/eventTypes/user.delete',
39-
'google.firebase.analytics.log.v1.written':
40-
'providers/google.firebase.analytics/eventTypes/event.log',
41-
'google.firebase.database.document.v1.created':
42-
'providers/google.firebase.database/eventTypes/ref.create',
43-
'google.firebase.database.document.v1.written':
44-
'providers/google.firebase.database/eventTypes/ref.write',
45-
'google.firebase.database.document.v1.updated':
46-
'providers/google.firebase.database/eventTypes/ref.update',
47-
'google.firebase.database.document.v1.deleted':
48-
'providers/google.firebase.database/eventTypes/ref.delete',
49-
})
50-
);
51-
52-
// CloudEvent service names.
53-
const FIREBASE_AUTH_CE_SERVICE = 'firebaseauth.googleapis.com';
54-
const PUBSUB_CE_SERVICE = 'pubsub.googleapis.com';
55-
const STORAGE_CE_SERVICE = 'storage.googleapis.com';
22+
// Maps CloudEvent types to the equivalent GCF Event type
23+
export const CE_TO_BACKGROUND_TYPE: {[k: string]: string} = {
24+
'google.cloud.pubsub.topic.v1.messagePublished':
25+
'google.pubsub.topic.publish',
26+
'google.cloud.storage.object.v1.finalized': 'google.storage.object.finalize',
27+
'google.cloud.storage.object.v1.deleted': 'google.storage.object.delete',
28+
'google.cloud.storage.object.v1.archived': 'google.storage.object.archive',
29+
'google.cloud.storage.object.v1.metadataUpdated':
30+
'google.storage.object.metadataUpdate',
31+
'google.cloud.firestore.document.v1.written':
32+
'providers/cloud.firestore/eventTypes/document.write',
33+
'google.cloud.firestore.document.v1.created':
34+
'providers/cloud.firestore/eventTypes/document.create',
35+
'google.cloud.firestore.document.v1.updated':
36+
'providers/cloud.firestore/eventTypes/document.update',
37+
'google.cloud.firestore.document.v1.deleted':
38+
'providers/cloud.firestore/eventTypes/document.delete',
39+
'google.firebase.auth.user.v1.created':
40+
'providers/firebase.auth/eventTypes/user.create',
41+
'google.firebase.auth.user.v1.deleted':
42+
'providers/firebase.auth/eventTypes/user.delete',
43+
'google.firebase.analytics.log.v1.written':
44+
'providers/google.firebase.analytics/eventTypes/event.log',
45+
'google.firebase.database.document.v1.created':
46+
'providers/google.firebase.database/eventTypes/ref.create',
47+
'google.firebase.database.document.v1.written':
48+
'providers/google.firebase.database/eventTypes/ref.write',
49+
'google.firebase.database.document.v1.updated':
50+
'providers/google.firebase.database/eventTypes/ref.update',
51+
'google.firebase.database.document.v1.deleted':
52+
'providers/google.firebase.database/eventTypes/ref.delete',
53+
};
5654

5755
const PUBSUB_MESSAGE_TYPE =
5856
'type.googleapis.com/google.pubsub.v1.PubsubMessage';
@@ -62,11 +60,6 @@ const PUBSUB_MESSAGE_TYPE =
6260
*/
6361
const CE_SOURCE_REGEX = /\/\/([^/]+)\/(.+)/;
6462

65-
/**
66-
* Costom exception class to represent errors durring event converion.
67-
*/
68-
export class EventConversionError extends Error {}
69-
7063
/**
7164
* Is the given request a known CloudEvent that can be converted to a legacy event.
7265
* @param request express request object
@@ -75,7 +68,7 @@ export class EventConversionError extends Error {}
7568
const isConvertableCloudEvent = (request: Request): boolean => {
7669
if (isBinaryCloudEvent(request)) {
7770
const ceType = request.header('ce-type');
78-
return CE_TO_BACKGROUND_TYPE.has(ceType!);
71+
return !!ceType && ceType in CE_TO_BACKGROUND_TYPE;
7972
}
8073
return false;
8174
};
@@ -117,7 +110,7 @@ const marshallConvertableCloudEvent = (
117110
let resource: string | {[key: string]: string} = `${name}/${subject}`;
118111

119112
switch (service) {
120-
case PUBSUB_CE_SERVICE:
113+
case CE_SERVICE.PUBSUB:
121114
// PubSub resource format
122115
resource = {
123116
service: service,
@@ -129,7 +122,7 @@ const marshallConvertableCloudEvent = (
129122
data = data.message;
130123
}
131124
break;
132-
case FIREBASE_AUTH_CE_SERVICE:
125+
case CE_SERVICE.FIREBASE_AUTH:
133126
// FirebaseAuth resource format
134127
resource = name;
135128
if ('metadata' in data) {
@@ -144,7 +137,7 @@ const marshallConvertableCloudEvent = (
144137
}
145138
}
146139
break;
147-
case STORAGE_CE_SERVICE:
140+
case CE_SERVICE.STORAGE:
148141
// CloudStorage resource format
149142
resource = {
150143
name: `${name}/${subject}`,
@@ -158,7 +151,7 @@ const marshallConvertableCloudEvent = (
158151
context: {
159152
eventId: ceContext.id!,
160153
timestamp: ceContext.time!,
161-
eventType: CE_TO_BACKGROUND_TYPE.get(ceContext.type!),
154+
eventType: CE_TO_BACKGROUND_TYPE[ceContext.type!],
162155
resource,
163156
},
164157
data,

0 commit comments

Comments
 (0)