Skip to content

Commit b01b075

Browse files
authored
Implement client-side Firebase Cloud Functions locations (#23)
* Implement client-side Firebase Cloud Functions locations Allows client-side Functions calls to remote functions using a supported Region (Android & iOS) or Custom Domain (iOS only). See https://firebase.google.com/docs/functions/locations#client-side_location_selection_for_callable_functions Adds a method to FirebaseApp ('functions') to set Region or CustomDomain. Example usage: firebase().app().functions("europe-west") See https://firebase.google.com/docs/reference/node/firebase.app.App#functions Example client-side call: firebase().functions().httpsCallable('functionName')() calls Cloud Function: exports functionName = functions.region('europe-west1')... See https://firebase.google.com/docs/functions/locations#best_practices_for_changing_region Supported regions: See https://firebase.google.com/docs/functions/locations By default functions run in the "us-central1" region, unless another region is selected. Android Functions Emulator: Set 'localhost' host to 10.0.2.2 * Update README.md file with usage instructions * Update README.md file with usage instructions * Clenaup README.md text
1 parent 53bcff4 commit b01b075

File tree

4 files changed

+147
-8
lines changed

4 files changed

+147
-8
lines changed

packages/firebase-functions/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,41 @@ firebase()
4848
});
4949
```
5050

51+
## Regional Cloud Functions
52+
Cloud Functions are _regional_, which means the infrastructure that runs your Cloud Function is located in specific regions.
53+
54+
By default, functions run in the _us-central1_ region. View the [supported regions](https://firebase.google.com/docs/functions/locations).
55+
56+
To run functions in a different region, after initializing Firebase App set the region using _firebase().app().functions(region)_.
57+
58+
Regional function endpoint example (using _europe-west2_ region ):
59+
```ts
60+
// Deployed HTTPS callable
61+
exports.listProducts = functions.region("europe-west2").https.onCall(() => {
62+
return [
63+
/* ... */
64+
// Return some data
65+
];
66+
});
67+
```
68+
69+
To access the regional function endpoint:
70+
```ts
71+
import { firebase } from '@nativescript/firebase-core';
72+
import '@nativescript/firebase-functions';
73+
74+
firebase().initializeApp();
75+
firebase().app().functions("europe-west2");
76+
77+
firebase()
78+
.functions()
79+
.httpsCallable('listProducts')()
80+
.then((response) => {
81+
setProducts(response.data);
82+
setLoading(false);
83+
});
84+
```
85+
5186
## Using an emulator
5287

5388
Whilst developing your application with Cloud Functions, it is possible to run the functions inside of a local emulator.

packages/firebase-functions/index.android.ts

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ import {
33
HttpsCallable,
44
HttpsCallableOptions,
55
HttpsErrorCode,
6-
IFunctions,
6+
IFunctions
77
} from "./common";
88
import {deserialize, firebase, FirebaseApp, serialize} from "@nativescript/firebase-core";
99

10-
1110
let defaultFunctions: Functions;
1211

1312
const fb = firebase();
@@ -24,6 +23,31 @@ Object.defineProperty(fb, 'functions', {
2423
},
2524
writable: false,
2625
});
26+
/**
27+
Firebase Functions Region - Region for which to run HttpsCallable method
28+
Set parameter using firebase().app().functions(regionOrCustomDomain: string)
29+
@see https://firebase.google.com/docs/reference/android/com/google/firebase/functions/FirebaseFunctions
30+
@note If not set, default region is used ("us-central1")
31+
*/
32+
let defaultRegionOrCustomDomain: string;
33+
/**
34+
Add 'functions' method to FirebaseApp class
35+
@see https://firebase.google.com/docs/reference/node/firebase.app.App
36+
@see https://firebase.google.com/docs/functions/locations
37+
@param regionOrCustomDomain(string)(Optional): Name of the region for which to Functions results
38+
@return Functions
39+
*/
40+
const fbApp = FirebaseApp;
41+
Object.defineProperty(fbApp.prototype, 'functions', {
42+
value: (regionOrCustomDomain?: string) => {
43+
defaultRegionOrCustomDomain = regionOrCustomDomain;
44+
if (!defaultFunctions) {
45+
defaultFunctions = new Functions();
46+
}
47+
return defaultFunctions;
48+
},
49+
writable: false,
50+
});
2751

2852

2953
function errorToCode(error: com.google.firebase.functions.FirebaseFunctionsException.Code) {
@@ -130,13 +154,19 @@ export class Functions implements IFunctions {
130154

131155
constructor(app?: FirebaseApp) {
132156
if (app?.native) {
133-
this.#native = com.google.firebase.functions.FirebaseFunctions.getInstance(app.native);
157+
this.#native = defaultRegionOrCustomDomain
158+
? com.google.firebase.functions.FirebaseFunctions.getInstance(app.native, defaultRegionOrCustomDomain)
159+
: com.google.firebase.functions.FirebaseFunctions.getInstance(app.native);
134160
} else {
135161
if(defaultFunctions){
136162
return defaultFunctions;
137163
}
138164
defaultFunctions = this;
139-
this.#native = com.google.firebase.functions.FirebaseFunctions.getInstance();
165+
// If defaultRegionOrCustomDomain is set, get FirebaseFunctions instance using that parameter
166+
// @see https://firebase.google.com/docs/functions/locations#client-side_location_selection_for_callable_functions
167+
this.#native = defaultRegionOrCustomDomain
168+
? com.google.firebase.functions.FirebaseFunctions.getInstance(defaultRegionOrCustomDomain)
169+
: com.google.firebase.functions.FirebaseFunctions.getInstance();
140170
}
141171
}
142172

@@ -162,7 +192,7 @@ export class Functions implements IFunctions {
162192
}
163193

164194
useEmulator(host: string, port: number) {
165-
this.native.useEmulator(host, port);
195+
this.native.useEmulator(host === 'localhost' ? '10.0.2.2' : host, port);
166196
}
167197

168198
get native() {

packages/firebase-functions/index.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,22 @@ export declare class Functions implements IFunctions {
2626
}
2727

2828
declare module '@nativescript/firebase-core' {
29+
2930
export interface Firebase extends FirebaseFunctions {}
31+
// Add 'functions' method to FirebaseApp
32+
export interface FirebaseApp extends FirebaseFunctionsApp {}
3033
}
3134

3235
export interface FirebaseFunctions {
3336
static functions(app?: FirebaseApp): Functions;
3437
}
38+
/**
39+
Add Region (Android & iOS) or Custom Domain (iOS only) to Firebase Functions HTTPS call
40+
@param regionOrCustomDomain (string) (optional): Region (Android or iOS) or Custom Domain (iOS only)
41+
@return Functions
42+
@see Supported Regions: https://firebase.google.com/docs/functions/locations
43+
@example firebase().app().functions("us-central1")
44+
*/
45+
export interface FirebaseFunctionsApp {
46+
static functions(regionOrCustomDomain?: string): Functions;
47+
}

packages/firebase-functions/index.ios.ts

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
HttpsCallable,
44
HttpsCallableOptions,
55
HttpsErrorCode,
6-
IFunctions,
6+
IFunctions
77
} from "./common";
88
import {deserialize, firebase, FirebaseApp, serialize} from "@nativescript/firebase-core";
99

@@ -23,6 +23,34 @@ Object.defineProperty(fb, 'functions', {
2323
},
2424
writable: false,
2525
});
26+
/**
27+
Firebase Functions Region - Region for which to run HttpsCallable method
28+
Set parameter using firebase().app().functions(regionOrCustomDomain: string)
29+
@link https://firebase.google.com/docs/reference/node/firebase.app.App
30+
@link https://firebase.google.com/docs/reference/ios/firebasefunctions/api/reference/Classes/FIRFunctions
31+
@note If not set, default region is used ('us-central1')
32+
*/
33+
let defaultRegionOrCustomDomain: string;
34+
/**
35+
Add 'functions' method to FirebaseApp class
36+
@param regionOrCustomDomain(string)(Optional): Name of the Region or Custom Domain for which to Functions results
37+
@return Functions
38+
@see FirebaseFunctions
39+
@link https://firebase.google.com/docs/reference/ios/firebasefunctions/api/reference/Classes/FIRFunctions
40+
@see Supported Regions
41+
@see https://firebase.google.com/docs/functions/locations
42+
*/
43+
const fbApp = FirebaseApp;
44+
Object.defineProperty(fbApp.prototype, 'functions', {
45+
value: (regionOrCustomDomain?: string) => {
46+
defaultRegionOrCustomDomain = regionOrCustomDomain;
47+
if (!defaultFunctions) {
48+
defaultFunctions = new Functions();
49+
}
50+
return defaultFunctions;
51+
},
52+
writable: false,
53+
});
2654

2755
function errorToCode(error: NSError) {
2856
let code = HttpsErrorCode.UNKNOWN;
@@ -115,13 +143,29 @@ export class Functions implements IFunctions {
115143

116144
constructor(app?: FirebaseApp) {
117145
if (app?.native) {
118-
this.#native = FIRFunctions.functionsForApp(app.native);
146+
if(defaultRegionOrCustomDomain){
147+
this.#native = isRegion(defaultRegionOrCustomDomain) // Check whether a Region has been set
148+
? FIRFunctions.functionsForAppRegion(app.native, defaultRegionOrCustomDomain) // @see https://firebase.google.com/docs/reference/ios/firebasefunctions/api/reference/Classes/FIRFunctions#+functionsforapp:region:
149+
: isCustomDomain(defaultRegionOrCustomDomain) // Check whether using a Custom Domain has been set
150+
? FIRFunctions.functionsForAppCustomDomain(app.native, defaultRegionOrCustomDomain) // @see https://firebase.google.com/docs/reference/ios/firebasefunctions/api/reference/Classes/FIRFunctions#+functionsforapp:customdomain:
151+
: FIRFunctions.functionsForApp(app.native); // @see https://firebase.google.com/docs/reference/ios/firebasefunctions/api/reference/Classes/FIRFunctions#+functionsforapp:
152+
} else {
153+
this.#native = FIRFunctions.functionsForApp(app.native); // @see https://firebase.google.com/docs/reference/ios/firebasefunctions/api/reference/Classes/FIRFunctions#+functionsforapp:
154+
}
119155
} else {
120156
if(defaultFunctions){
121157
return defaultFunctions;
122158
}
123159
defaultFunctions = this;
124-
this.#native = FIRFunctions.functions();
160+
if(defaultRegionOrCustomDomain){
161+
this.#native = isRegion(defaultRegionOrCustomDomain) // Check whether a Region has been set
162+
? FIRFunctions.functionsForRegion(defaultRegionOrCustomDomain) // @see https://firebase.google.com/docs/reference/ios/firebasefunctions/api/reference/Classes/FIRFunctions#+functionsforregion:
163+
: isCustomDomain(defaultRegionOrCustomDomain) // Check whether using a Custom Domain has been set
164+
? FIRFunctions.functionsForCustomDomain(defaultRegionOrCustomDomain) // @see https://firebase.google.com/docs/reference/ios/firebasefunctions/api/reference/Classes/FIRFunctions#+functionsforcustomdomain:
165+
: FIRFunctions.functions(); // @see https://firebase.google.com/docs/reference/ios/firebasefunctions/api/reference/Classes/FIRFunctions#+functions
166+
} else {
167+
this.#native = FIRFunctions.functions(); // @see https://firebase.google.com/docs/reference/ios/firebasefunctions/api/reference/Classes/FIRFunctions#+functions
168+
}
125169
}
126170
}
127171

@@ -178,3 +222,20 @@ export class Functions implements IFunctions {
178222
return this.#app;
179223
}
180224
}
225+
/**
226+
Check whether a regionOrCustomDomain string is a Region for the http trigger, such as “us-central1”.
227+
@param regionOrCustomDomain(string): Text to parse
228+
@return boolean: TRUE if a Region; FALSE if not
229+
*/
230+
function isRegion(regionOrCustomDomain: string): boolean{
231+
const elems = regionOrCustomDomain.split('.');
232+
return elems.length === 1 ? true : false;
233+
}
234+
/**
235+
Check whether a regionOrCustomDomain string is a Custom Domain for the http trigger, such as “https://mydomain.com”
236+
@param regionOrCustomDomain(string): Text to parse
237+
@return boolean: TRUE if a CustomDomain; FALSE if not
238+
*/
239+
function isCustomDomain(regionOrCustomDomain: string): boolean{
240+
return !isRegion(regionOrCustomDomain);
241+
}

0 commit comments

Comments
 (0)