Skip to content

Commit f42518f

Browse files
authored
Firebase Cloud Messaging API (#187)
* New FCM API * Adding FCM unit tests * Added other FCM message types and tests * Minor cleanup * APNS message validation * Cleaned up tests * Improved error handling * Updated typings and integration tests * Updated typings * Added APNS types in the impl * Updated unit tests * Implemented dry run mode * Updated API; Implemented TTL numeric values; More test coverage * Boosted test coverage to almost 100% * Updated changelog * Changing test data * Adding some documentation; Addressing some code review feedback * Accept prefixed topic names (#203) * Accept prefixed topic names * Further validating topic names * Handling the New FCM Error Codes (#206) * Using new FCM error codes * Adding new SDK error code message-rate-exceeded * Updated changelog
1 parent 5c4b523 commit f42518f

File tree

7 files changed

+1226
-7
lines changed

7 files changed

+1226
-7
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Unrelased
22

3-
-
3+
- [added] Added the `messaging.send()` method and the new `Message` type for
4+
sending Cloud Messaging notifications via the
5+
[new FCM REST endpoint](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages).
46

57
# v5.8.2
68

src/index.d.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,99 @@ declare namespace admin.database.ServerValue {
292292
var TIMESTAMP: number;
293293
}
294294

295+
type BaseMessage = {
296+
data?: {[key: string]: string};
297+
notification?: admin.messaging.Notification;
298+
android?: admin.messaging.AndroidConfig;
299+
webpush?: admin.messaging.WebpushConfig;
300+
apns?: admin.messaging.ApnsConfig;
301+
};
302+
303+
interface TokenMessage extends BaseMessage {
304+
token: string;
305+
}
306+
307+
interface TopicMessage extends BaseMessage {
308+
topic: string;
309+
}
310+
311+
interface ConditionMessage extends BaseMessage {
312+
condition: string;
313+
}
314+
295315
declare namespace admin.messaging {
316+
type Message = TokenMessage | TopicMessage | ConditionMessage;
317+
318+
type AndroidConfig = {
319+
collapseKey?: string;
320+
priority?: ('high'|'normal');
321+
ttl?: number;
322+
restrictedPackageName?: string;
323+
data?: {[key: string]: string};
324+
notification?: AndroidNotification;
325+
};
326+
327+
type AndroidNotification = {
328+
title?: string;
329+
body?: string;
330+
icon?: string;
331+
color?: string;
332+
sound?: string;
333+
tag?: string;
334+
clickAction?: string;
335+
bodyLocKey?: string;
336+
bodyLocArgs?: string[];
337+
titleLocKey?: string;
338+
titleLocArgs?: string[];
339+
};
340+
341+
type ApnsConfig = {
342+
headers?: {[key: string]: string};
343+
payload?: ApnsPayload;
344+
};
345+
346+
type ApnsPayload = {
347+
aps: Aps;
348+
[customData: string]: object;
349+
};
350+
351+
type Aps = {
352+
alert?: string | ApsAlert;
353+
badge?: number;
354+
sound?: string;
355+
contentAvailable?: boolean;
356+
category?: string;
357+
threadId?: string;
358+
};
359+
360+
type ApsAlert = {
361+
title?: string;
362+
body?: string;
363+
locKey?: string;
364+
locArgs?: string[];
365+
titleLocKey?: string;
366+
titleLocArgs?: string[];
367+
actionLocKey?: string;
368+
launchImage?: string;
369+
};
370+
371+
type Notification = {
372+
title?: string;
373+
body?: string;
374+
};
375+
376+
type WebpushConfig = {
377+
headers?: {[key: string]: string};
378+
data?: {[key: string]: string};
379+
notification?: WebpushNotification;
380+
};
381+
382+
type WebpushNotification = {
383+
title?: string;
384+
body?: string;
385+
icon?: string;
386+
};
387+
296388
type DataMessagePayload = {
297389
[key: string]: string;
298390
};
@@ -366,6 +458,7 @@ declare namespace admin.messaging {
366458
interface Messaging {
367459
app: admin.app.App;
368460

461+
send(message: admin.messaging.Message, dryRun?: boolean): Promise<string>;
369462
sendToDevice(
370463
registrationToken: string | string[],
371464
payload: admin.messaging.MessagingPayload,

src/messaging/messaging-api-request.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ export class FirebaseMessagingRequestHandler {
4545
if (validator.isNonNullObject(response) && 'error' in response) {
4646
if (typeof response.error === 'string') {
4747
return response.error;
48+
} else if ('status' in response.error) {
49+
return response.error.status;
4850
} else {
4951
return response.error.message;
5052
}
@@ -53,6 +55,21 @@ export class FirebaseMessagingRequestHandler {
5355
return null;
5456
}
5557

58+
/**
59+
* Extracts error message from the given response object.
60+
*
61+
* @param {object} response The response to check for errors.
62+
* @return {string|null} The error message if present; null otherwise.
63+
*/
64+
private static getErrorMessage(response: any): string | null {
65+
if (validator.isNonNullObject(response) &&
66+
'error' in response &&
67+
validator.isNonEmptyString(response.error.message)) {
68+
return response.error.message;
69+
}
70+
return null;
71+
}
72+
5673
/**
5774
* @param {FirebaseApp} app The app used to fetch access tokens to sign API requests.
5875
* @constructor
@@ -138,7 +155,8 @@ export class FirebaseMessagingRequestHandler {
138155

139156
// For JSON responses, map the server response to a client-side error.
140157
const errorCode = FirebaseMessagingRequestHandler.getErrorCode(response.error);
141-
throw FirebaseMessagingError.fromServerError(errorCode, /* message */ undefined, response.error);
158+
const errorMessage = FirebaseMessagingRequestHandler.getErrorMessage(response.error);
159+
throw FirebaseMessagingError.fromServerError(errorCode, errorMessage, response.error);
142160
});
143161
}
144162
}

0 commit comments

Comments
 (0)