httpsCallableFromURL
is working correctly but httpsCallable
is returning null
. What’s wrong?
The emulator logs show that the Cloud Function executes correctly from both httpsCallableFromURL
and httpsCallable
. My browser console logs UPPERCASE
(if I enter uppercase
) with httpsCallableFromURL
. But with httpsCallable
the browser console logs null
.
It seems like null
logs almost instantly but UPPERCASE
takes a moment to log. My guess is that the return is executing before the function?
And another question. I found the URL in the Firebase Console in the list of Functions, for the deployed function. Is there somewhere in the emulator where I can find the URL for calling the function in the emulator? This URL was written by Github Copilot! This URL also works: http://localhost:5001/my-projectId/us-central1/upperCaseMe
index.ts
import * as functions from "firebase-functions";
export const upperCaseMe = functions.https.onCall((data, context) => {
const original = data.text;
const uppercase = original.toUpperCase();
functions.logger.log('upperCaseMe', original, uppercase);
return uppercase;
});
app.component.ts
import { Component } from '@angular/core';
import { getFunctions, httpsCallable, httpsCallableFromURL } from "firebase/functions";
import { initializeApp } from 'firebase/app';
import { environment } from '../environments/environment';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
firebaseConfig = environment.firebaseConfig;
firebaseApp = initializeApp(this.firebaseConfig);
messageText: any;
functions = getFunctions(this.firebaseApp);
callMe(messageText: any) {
console.log("Calling Cloud Function: " + messageText);
// const upperCaseMe = httpsCallable(this.functions, 'upperCaseMe');
const upperCaseMe = httpsCallableFromURL(this.functions, 'http://127.0.0.1:5001/my-projectId/us-central1/upperCaseMe');
upperCaseMe({ text: messageText })
.then((result) => {
console.log(result.data)
})
.catch((error) => {
console.error(error);
});;
};
}
I was able to make httpsCallableFromURL
return null
:
import * as functions from "firebase-functions";
export const upperCaseMe = functions.https.onCall((data, context) => {
const original = data.text;
const uppercase = original.toUpperCase();
setTimeout(() => {
console.log("Wait ten seconds.");
functions.logger.log('upperCaseMe', original, uppercase);
return uppercase;
}, 10000)
});
This never logs anything in the emulator and always logs null
in the browser console. It logs null
after a second or two, not ten seconds. Same results with httpsCallableFromURL
and httpsCallable
.
2
Answers
I initialized Firebase incorrectly. Firebase should be initialized in
app.module.ts
, not inapp.component.ts
. Firebase should then be injected intoapp.component.ts
. When I initialized Firebase correctly then bothhttpsCallable
andhttpsCallableFromURL
returned the UPPERCASE message to the browser console.app.module.ts
I changed the view to pass the message only via
ngModel
. Passing the message viacallMe(messageText)
was redundant.app.component.html
I changed the component controller to inject
Functions
rather than initialize Firebase in the component controller:app.component.ts
No changes to
index.ts
.As for Doug Stevenson's comment that the last code block in my question made him cringe, I reread the Cloud Functions documentation Sync, async, and promises which explained that
return
is synchronous and promises are async. I promise never to put areturn
in a promise again!httpsCallable
uses your deployed code hosted by Cloud Functions by default. The URL is derived from the data you passed during initialization of the Firebase SDK. It does not use the emulator unless you configure the SDK to do so. I suggest reviewing the documentation on the matter.httpsCallableFromURL
is for cases when you cannot use the normal way that the SDK locates the backend, for example, if you are hosting the callable function on some service that is not a normal Cloud Functions backend, or you are trying to invoke a function in a project that’s not part of your app.I would never expect Copilot to generate the correct code under any circumstance. It’s better to lean on the documentation to tell you what to do.