Firebase - Functions does not allow me to set region - javascript

I am trying to set a region to deploy my functions. According to the documentation I have to do:
var functions = firebase.app().functions('us-west2');
But when I do this and then try to deploy I get an error:
Error: Error occurred while parsing your function triggers.
TypeError: Cannot read property 'onCall' of undefined
If I change functions definitions back to default:
const functions = require("firebase-functions");
It works, any ideas why I get this error?
Sample Code:
const firebase = require("firebase");
const admin = require("firebase-admin");
require("firebase-functions");
firebase.initializeApp({...})
admin.initializeApp()
let functions = firebase.app().functions('us-east1')
exports.findUserInAuth = functions.https.onCall((data, context) => {..}

I think you're reading the documentation incorrectly.
If this is a most basic definition of a callable function, as suggested by the documentation:
const functions = require("firebase-functions");
exports.findUserInAuth = functions.https.onCall((data, context) => {
// ...
});
Then, to change the region, you need to insert some more method calls in the builder for that function:
const functions = require("firebase-functions");
exports.findUserInAuth = functions.https.region('us-west2').onCall((data, context) => {
// ...
});
The code on the frontend client will not use firebase-functions. You have to use the instructions for setting up the client later on that page. Setting the region on the client works differently.

Related

Firebase function for Algolia returns undefined

I am following the Firebase tutorial on how to implement Algolia with Firebase: https://firebase.google.com/docs/firestore/solutions/search
I am currently stuck on the indexing part of the tutorial as I have errors coming from the firebase cloud-functions logs.
This is the output of the cloud-functions log
and this is the code I wrote
const functions = require('firebase-functions');
const algoliasearch = require("algoliasearch");
const ALGOLIA_ID = functions.config().algolia.app;
const ALGOLIA_ADMIN_KEY = functions.config().algolia.key;
const ALGOLIA_SEARCH_KEY = functions.config().algolia.search_key;
const ALGOLIA_INDEX_NAME = 'users';
const client = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY);
// Update the search index every time a blog post is written.
exports.onUserCreated = functions.firestore.document('organisations/40R0LMA6ALZgF7KjHJMc/employees/{userId}').onCreate((snap, context) => {
// Get the note document
const user = snap.data();
// Add an 'objectID' field which Algolia requires
user.objectID = snap.id;
console.log(user.objectID)
// Write to the algolia index
const index = client.initIndex(ALGOLIA_INDEX_NAME);
return index.saveObject(user);
});
It seems that you are not correctly setting the different environment variables used in this example.
As explained in the doc, to get the value of the algolia.app environment variable when you do const ALGOLIA_ID = functions.config().algolia.app; you need to previously set its value as follows:
firebase functions:config:set algolia.app="THE_ALGOLIA_ID"
Since you need to set several variables, you can set them in one instruction, as follows:
firebase functions:config:set algolia.app="THE_ALGOLIA_ID" algolia.key="THE_ALGOLIA_ADMIN_KEY" ...
As explained in the doc, "to inspect what's currently stored in environment config for your project, you can use firebase functions:config:get" in the CLI.

How to access snapshot of Firebase database within Firebase Function?

Every hour, I want my firebase function to look through my database, read a value, calculate a new value from this old value, and then update it in the database. I am having trouble accessing a snapshot of the data. Specificically,
exports.scheduledFunction = functions.pubsub.schedule('every 1 hour').onRun((context) => {
const ref = functions.database.ref('/users/test_user/commutes');
ref.once('value',function(snapshot) {
// do new calculation here
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
return null;
});
I am getting a : functions: TypeError: ref.once is not a function error.
How do I access a value from my firebase real time database and update it from a Firebase function?
You're trying to use the firebase-functions SDK to query the database. It can't do that. You will have to use the Firebase Admin SDK to make the query.
You will need to get started like this (not complete, but you should be able to see what you need to do). Import and initialize at the global scope:
const admin = require('firebase-admin')
admin.initializeApp()
Then in your function, use it. Be sure to work with promises correctly.
const ref = admin.database().ref('...')
return ref.once('value').then(snapshot => {
// work with the snapshot here, and return another promise
// that resolves after all your updates are complete
})
The firebase-functions is different from the client side. The ref() function according to the docs:
ref: function
ref(path: string): RefBuilder
Select Firebase Realtime Database Reference to listen to.
Path of the database to listen to.
Returns RefBuilder
The RefBuilder will contain the database triggers that you can call, onCreate(), onWrite(). To be able to use your database, then you need to use the admin sdk.
https://firebase.google.com/docs/reference/functions/providers_database_.refbuilder

Firebase cloud function onCreate not running?

I've been following a tutorial (https://www.youtube.com/watch?v=9kRgVxULbag&t=1108s) and I'm trying to get .onCreate to work, but nothing's happening.
The code I'm trying to replicate is at around 19:30 in the video, and here's what I've got:
exports.createinvite = functions.firestore
.document('referrals/{referralid}')
.onCreate(event => {
console.log('asfasdfasdf')
const docid = event.params.referralid;
const code = event.data.data().thing;
const referralref = admin.filestore().collection('referrals').doc(docid)
return referralref.update({message: `asfasfasdfa`})
});
Any help is appreciated :)
You are following a very old tutorial, and I suggest you stop following it and learn from something newer, such as the official Firebase videos on YouTube. The APIs have changed.
Please also follow the documentation for Firestore triggers to learn what an onCreate function looks like today. They take two parameters, a snapshot and a context:
exports.createinvite = functions.firestore
.document('referrals/{referralid}')
.onCreate((snapshot, context) => { ... })
The wildcards from the pattern are available in context.params. You will use context.params.referralid to get the value of the wildcard.
If you look at the documentation for Firestore event triggers, you'll see that onCreate is called with two parameters: snapshot and context. The params property exists on the context/second parameter, and not on the first.
So:
exports.createinvite = functions.firestore
.document('referrals/{referralid}')
.onCreate((snapshot, context) => {
console.log('asfasdfasdf')
const docid = context.params.referralid;
const code = snapshot.data().thing;
...
I highly recommend checking out the documentation if something from a tutorial doesn't work, as the product may have been updated since the tutorial was created.

Update another location onUpdate with firebase cloud functions [duplicate]

This question already has answers here:
Firebase DB - How to update particular value of child in Firebase Database
(3 answers)
Closed 4 years ago.
I am trying to keep some data consistent with firebase cloud functions. When data changes in the main list, I want all the data to change in the user's favourite list.
Currently, I am able to call the function and get a log of the correct data which is changing, but my query doesn't work. I am getting the following error:
TypeError: ref.update is not a function
at exports.itemUpdate.functions.database.ref.onUpdate
Here is my code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.itemUpdate = functions.database
.ref('/items/{itemId}')
.onUpdate((change, context) => {
const before = change.before.val(); // DataSnapshot after the change
const after = change.after.val(); // DataSnapshot after the change
console.log(after);
if (before.effects === after.effects) {
console.log('effects didnt change')
return null;
}
const ref = admin.database().ref('users')
.orderByChild('likedItems')
.equalTo(before.title);
console.log(ref);
return ref.update(after);
});
I'm not to sure where I am going wrong, I appreciate all the help and guidance to resolve this!
Cheers.
equalTo() returns a Query object. You're then trying to call update() on that object. Note that in the linked API docs, Query doesn't have an update() method. You can't simply "update" a Query that hasn't been performed. You're going to have to actually perform the query using once(), iterate the results form the snapshot in the returned promise, and perform further updates using the data you find.

Using Jest spyOn a module that is initiated

Within an ExpresS API I'm using the Postmark library to send an email, which is initiated like this:
var postmark = require("postmark");
var client = new postmark.Client("aaaa-bbbbb-cccc");
And then used to send a password reset mail later on with:
client.sendEmailWithTemplate(
// Options here
);
Now, I would like to test this function has been called, but I have difficulties finding out how to mock/spy on this.
I have tried the following (simplified):
const request = require("supertest");
const app = require("../server/app");
const postmark = require("postmark");
jest.mock("postmark");
describe("API Tests", () => {
test("it should give a reset link when requesting with existing e-mail address", () => {
return request(app)
.post("/api/auth/passwordreset")
.send({
email: "user1#test.test"
})
.then(response => {
expect(postmark.Client).toHaveBeenCalled();
});
});
});
This works, but it's only testing if postmark has been used, since I can't figure out how to actually test the client.sendEmailWithTemplate method
Any suggestions on how to accomplish this?
EDIT: following up on #samanime answer I created a repo to illustrate the 'challenge'
https://github.com/Hyra/jest_test_example
You can specifically mock out the Client function that is returned by the mocked postmark to return an object with mocked functions.
In Jest, you can provide specific mocking code for a node_modules by creating a folder named __mocks__ at the same level as node_modules, i.e.,
/project-root
/node_modules
/__mocks__
Note, that is two underscores on each side.
In there, make a function named <package_name>.js (in your case, postmark.js). It will then load whatever is exported by that when you use the mock.
In that file, you can mock it out as needed. Something like this would probably work:
// global jest
module.exports = {
Client: jest.fn(() => ({
sendEmailWithTemplate: jest.fn(() => {})
}))
};
It doesn't have to be as compact as this, but basically it makes postmark have a function called Client which returns an object that has a functiono called sendEmailWithTemplate, both of which are mocks/spys.
Then you can just check if postmark.Client.sendEmailWithTemplate was called.
The one gotcha is you'll need to be sure to reset all of these in between tests. You could do this manually in your beforeEach(), but if you are going to reuse it, I like to add an extra function named __reset() which will reset the code and just call that:
// global jest
const mockedPostmark = {
Client: jest.fn(() => ({
sendEmailWithTemplate: jest.fn(() => {})
}))
};
mockedPostmark.__reset = () => {
mockedPostmark.Client.mockClear();
mockedPostmark.Client.sendEmailWithTemplate.mockClear();
};
module.exports = mockedPostmark;
You can add additional functions as needed as well.

Categories