Firebase cloud functions https, calling API not working for me - firebase

I'm trying to learn firebase cloud functions and I want to call an API using it but the console log shows that no data is being fetched, even though the function is deployed successfully/
Firebase function:
const functions = require('firebase-functions');
const axios = require('axios');
exports.fetchList = functions.https.onRequest((request, response) =>{
axios.get('https://rallycoding.herokuapp.com/api/music_albums').then((data) =>{
response.send(data)
}).catch((e) =>{
console.log(e)
})
})
App component:
componentWillMount() {
axios({
method:'POST',
url: 'link from the console website',
}).then((data) =>{
console.log(data.data);
}).catch((e) =>{
console.log(e);
})
}

If you want to see that data from the fetchList data logged to the Firebase console, you need to insert a console.log before you send a response.
const dataToLog = axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(dataToLog => {
console.log(dataToLog);
response.send(dataToLog);
}).catch // etc.
Also, probably obvious, but of course you'd need to put in the actual function URL endpoint in your component, not the string link from the console website.
Apologies if I'm misunderstanding your question!

Related

Error when using Spotify access token with API through Firebase callable cloud function

I've been working on this for a while now and feel like I've read everything I can find but still can't get it to work. I'm trying to build a Firebase callable cloud function that uses axios to get a Spotify access token through client credentials auth flow and then uses that token to get data from my own account from the Spotify API. I'm using a chained function starting with axios.post and then axios.get.
The code works when it's getting the access token through axios.post but as soon as I chain an axios.get to use the token with the API something goes wrong. I'm new to Firebase and node.js so am not sure exactly how to catch the errors properly. The most common error is either a null result or a 'Unhandled error RangeError: Maximum call stack size exceeded' in the Firebase log... can't work out what either actually means for my code... With this particular version of my code I get a null result and a mass of around 50 different error logs in Firebase.
I've tried splitting the functions, using async and await and different arrangements of the headers but not a lot really changes. I've found similar questions but nothing that seemed to solve the issue. Any help would be amazing!
const functions = require("firebase-functions");
const axios = require('axios');
const qs = require('qs');
exports.spot = functions.https.onCall( async (data, context) => {
const client_id = //REMOVED;
const client_secret = //REMOVED;
const auth_token = Buffer.from(`${client_id}:${client_secret}`, 'utf-8').toString('base64');
const token_url = 'https://accounts.spotify.com/api/token';
const stringify_data = qs.stringify({'grant_type':'client_credentials'});
const api_url = 'https://api.spotify.com/v1/recommendations'
return axios
.post(token_url, stringify_data, {
headers: {
'Authorization': `Basic ${auth_token}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
grant_type: 'client_credentials'
},
json: true
})
.then(result => {
return axios.get(api_url, {
headers: {
'Authorization': `Bearer ${result.data.access_token}`,
}
})
})
.then(result => {
return result
})
.catch(error => {
console.log(error);
})
});

Cloud Firestore emulator not running when using firebase serve method

I've been trying to implement some Cloud Functions that get and post data from Cloud Firestore(I'm using postman). I want to test these locally, however I cannot get the Cloud Firestore emulator to run.
My index.js file
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const express = require("express");
admin.initializeApp();
const app = express();
app.get("/posts", (req, res) => {
admin
.firestore()
.collection("posts")
.orderBy("createdAt", "desc")
.get()
.then((data) => {
let posts = [];
data.forEach((doc) => {
posts.push({
postId: doc.id,
body: doc.data().body,
userHandle: doc.data().userHandle,
createdAt: doc.data().createdAt,
});
});
return res.json(posts);
})
.catch((err) => console.log(err));
});
app.post("/post", (req, res) => {
const newPost = {
body: req.body.body,
userHandle: req.body.userHandle,
createdAt: new Date().toISOString(),
};
admin
.firestore()
.collection("posts")
.add(newPost)
.then((doc) => {
res.json({ message: `document ${doc.id} created successfully` });
})
.catch((err) => {
res.status(500).json({ error: "something went wrong" });
console.log(err);
});
});
exports.api = functions.https.onRequest(app);
I can get data when never i use firebase deploy method using postman.
result for firebase deploy method is response (status:200) [in postman]
However if i try firebase serve or firebase serve --only function . i get like this...
firebase serve
=== Serving from 'C:\Users\Yuvan M\Documents\Visual Studio Code\React\meme-zha\meeme-functions'...
! Your requested "node" version "8" doesn't match your global version "12"
i functions: Watching "C:\Users\Yuvan M\Documents\Visual Studio Code\React\meme-zha\meeme-functions\functions" for Cloud Functions...
+ functions[api]: http function initialized (http://localhost:5000/meeme-zha/us-central1/api)
in above code i can't get response like
i functions : preparing emulate function.
if i use this local address http://localhost:5000/meeme-zha/us-central1/api , this gives me the error like this...
! functions: The Cloud Firestore emulator is not running, so calls to Firestore will affect production.
! External network resource requested!
I use firebase emulator:start - not working.I tried every solution that posted on internet for this kind of problem, also i followed the documentation . still i can't solve it.

Why can I call firestore from a firebase function using onRequest, but not when using onCall

I have two firebase functions deployed, one uses functions.https.onRequest (companyRequest) and one uses functions.https.onCall (companyCall). Both do the exact same thing: retrieve a document from firestore (the exact same document from the exact same collection).
Here are the functions:
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
admin.initializeApp(functions.config().firebase);
export const companyRequest = functions.https.onRequest((request, response) => {
const companyId = "VpOVFo82m9ls3aIK7dra";
admin
.firestore()
.collection("company")
.doc(companyId)
.get()
.then(result => {
response.send(result.data());
})
.catch(error => {
response.send(error);
});
});
export const companyCall = functions.https.onCall((data, context) => {
if (context && context.auth) {
console.log(
"AUTH",
context.auth.uid,
context.auth.token.email
);
}
const companyId = "VpOVFo82m9ls3aIK7dra";
admin
.firestore()
.collection("company")
.doc(companyId)
.get()
.then(result => {
return result.data();
})
.catch(error => {
return error;
});
});
I call companyRequest with curl and it works:
> curl https://us-central1-xxxxx.cloudfunctions.net/company
{"name":"Duny Comp."}
I call companyCall from flutter and it fails (on firebase, server site):
Future click() async {
final HttpsCallable callable = CloudFunctions.instance.getHttpsCallable(
functionName: 'companyCall',
);
HttpsCallableResult resp = await callable.call(<String, dynamic>{
'companyId': 'VpOVFo82m9ls3aIK7dra',
});
print(resp.data);
}
the error I get for companyCall is this:
AUTH 3gvfgYJpk2gIgUpkOLxdkdId uuuu#xxxx.com
ERROR: Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information
The error seems quite clear, but why does the unauthenticated call with curl work, but companyCall with firebase authentication via flutter does have a permission problems? In the output you can even see the auth information from the enduser in the flutter app, so he is authenticated.
The question is, why there is a difference between the two? The proposed solutions like Error: Could not load the default credentials (Firebase function to firestore) also feel very strange...
Update:
This is not the same question as in Firebase Cloud Functions: Difference between onRequest and onCall, in this question I ask why there is a difference in the security behaves different between the two different methods. Why do I need to authenticate with an admin account to access the same collection from onCall as I don't need it when access the collection from a onRequest method?

Using a callable function to send data back to the client from Firebase

I have created a callable Cloud Function to read data from Firebase and send back the results to the client, however, only "null" is being returned to the client.
exports.user_get = functions.https.onCall((data, context) => {
if (context.auth && data) {
return admin.firestore().doc("users/" + context.auth.uid).get()
.then(function (doc) {
return { doc.data() };
})
.catch(function (error) {
console.log(error);
return error;
})
} return
});
I just reproduced your case connecting from a Cloud Function with a Firestore database and retriving data. As I can see you are trying to access the field in a wrong way when you are using "users/" + context.auth.uid, the method can't find the field so its returning a null value.
I just followed this Quickstart using a server client library documentation to populate a Firestore database and make a Get from it with node.js.
After that i followed this Deploying from GCP Console documentation in order to deploy a HTTP triggered Cloud Function with the following function
exports.helloWorld = (req, res) => {
firestore.collection('users').get()
.then((snapshot) => {
snapshot.forEach((doc) => {
console.log(doc.id, '=>', doc.data().born);
let ans = {
date : doc.data().born
};
res.status(200).send(ans);
});
})
And this is returning the desired field.
You can take a look of my entire example code here
This is because you are making a query from a database firestore, however the cloud support team has made it very cool to protect your applications from data leakages and so in a callable function as the name suggest you can only return data you passed to the same callable function through the data parameter and nothing else. if you try to access a database i suggest you use an onRequest Function and use the endpoint to get you data. that way you not only protect your database but avoid data and memory leakage.
examples of what you can return from a callable function
exports.sayHello = functions.https.onCall((data, context) => {
const name = data.name;
console.log(`hello ${name}`);
return `It was really fun working with you ${name}`;
});
first create a function in your index.js file and accept data through the data parameter but as i said you can only return data you passed through the data parameter.
now call the function
this is in the frontend code (attach an event listener to a button or something and trigger it
/* jsut say hello from firebase */
callButton.addEventListener('click', () => {
const sayHello = firebase.functions().httpsCallable('getAllUsers');
sayHello().then(resutls => {
console.log("users >>> ", resutls);
});
});
you can get your data using an onRequest like so
/* get users */
exports.getAllUsers = functions.https.onRequest((request, response) => {
cors(request, response, () => {
const data = admin.firestore().collection("users");
const users = [];
data.get().then((snapshot) => {
snapshot.docs.forEach((doc) => {
users.push(doc.data());
});
return response.status(200).send(users);
});
});
});
using a fetch() in your frontend code to get the response of the new onRequest function you can get the endpoint to the function in your firebase console dashboard.
but not that to hit the endpoint from your frontend code you need to add cors to your firebase cloud functions to allow access to the endpoint.
you can do that by just adding this line to the top of your index.js file of the firebase functions directory
const cors = require("cors")({origin: true});

TypeError: functions.database is not a function

I want to update or creat an object, but i have this error :"TypeError: functions.database is not a function" on the registry of firebase function
this is my code:
const functions = require('firebase-functions');
exports.actualizar = functions.https.onRequest((request, response) => {
const obj = request.body;
const MAC = obj.MAC;
functions.database().ref ('/sensores/{MAC}').update(obj).promise.then(() =>
{
console.log("UpDate Success");
return req.status(200).send("ok");
})
.catch(() => {
functions.database.ref('/sensores'). set(obj).promise.then(() =>{
console.log ("Created Succces");
return req.status(200).send("");
})
.catch(() =>{
console.log("Error");
return req.status(500).send("error");
})
})
});
You can't use the Cloud Functions for Firebase SDK to query the database. It's just used for building the function definition. To query your database or other Firebase products, you need to use the Firebase Admin SDK, or whatever SDK is normally used to do so.
For example, you will see lots of official sample code that starts like this:
const admin = require('firebase-admin'); // this is the Admin SDK, not firebase-functions
admin.initializeApp();
// Then use "admin" to reach into Realtime Database, Firestore, Cloud Storage, etc.

Resources