Next.js with Firebase Remote Config - firebase

I was trying to integrate Google's Firebase Remote config into my Next.js app.
When following Firebase's docs, and just inserted the functions directly into my component's code block, like so:
const remoteConfig = getRemoteConfig(app);
I keep getting the following error when following their documentation:
FirebaseError: Remote Config: Undefined window object. This SDK only supports usage in a browser environment.

I understand that it happens since Nextjs is rendered server-side, so there's no window object yet, so here's my solution:
import {
fetchAndActivate,
getRemoteConfig,
getString,
} from 'firebase/remote-config';
const Home: NextPage<Props> = (props) => {
const [title, setTitle] = useState<string | null>('Is It True?');
useEffect(() => {
if (typeof window !== 'undefined') {
const remoteConfig = getRemoteConfig(app);
remoteConfig.settings.minimumFetchIntervalMillis = 3600000;
fetchAndActivate(remoteConfig)
.then(() => {
const titleData = getString(remoteConfig, 'trueOrFalse');
setTitle(titleData);
})
.catch((err) => {
console.log(err);
});
}
});
return <h1>{title}</h1>}
Basically, the important part is the if statement that checks if the window object exists, then it execute the Remote Config functions according to Firebase documents.
Also, it worked outside a useEffect, but I think that's probably a bad idea to leave it outside, maybe even it should have a dependency, can't think of one at the moment.

Related

Calling an API using Axios and Firebase Cloud Functions

I want to make a Google Cloud Function calling an external API for me. After some research on Google I found the way using Axios. The call is actually working, when I'm using it on my own nodejs but when I want to deploy the function to Google Cloud functions I'm always getting an error (Function cannot be initialized. Error: function terminated.)
I'm on the Blaze plan.
const functions = require("firebase-functions");
const axios = require("axios");
exports.getData = functions.https.onRequest((req, res) => {
return axios.get("http://api.marketstack.com/v1/eod?access_key='myAccessKey'&symbols=AAPL")
.then((response) => {
const apiResponse = response.data;
if (Array.isArray(apiResponse["data"])) {
apiResponse["data"].forEach((stockData) => {
console.log(stockData["symbol"]);
});
}
}).catch((error) => {
console.log(error);
});
});
Could someone please help me?
EDIT: I finally fixed it: the mistake was, that I ended up with two package.json files (one in the directory where it should be and one which I actually didn't need). When I was installing the dependencies with npm install, axios was added into the wrong package.json file. Unfortunately the other package.json file made it up to the server and I ended up with a package.json file without the necessary dependencies on the server and thus this made the error occur.
I didn’t test your code but you should return "something" (a value, null, a Promise, etc.) in the then() block to indicate to the Cloud Function platform that the asynchronous work is complete. See here in the doc for more details.
exports.getData = functions.https.onRequest((req, res) => {
return axios.get("http://api.marketstack.com/v1/eod?access_key='myAccessKey'&symbols=AAPL")
.then((response) => {
const apiResponse = response.data;
if (Array.isArray(apiResponse["data"])) {
apiResponse["data"].forEach((stockData) => {
console.log(stockData["symbol"]);
});
}
return null;
}).catch((error) => {
console.log(error);
});
});
You probably want do more than just logging values in the then() e.g. call an asynchronous Firebase method to write to a database (Firestore or the RTDB): in this case take care to return the Promise returned by this method.

How to use Coinbase SDK in a Server-Side Rendered app?

I was trying to follow the guide here to get user's wallet through Coinbase in my Next.js app:
https://docs.cloud.coinbase.com/wallet-sdk/docs/initializing
But I get this when I tried to render the component with the SDK initiating.
Server Error
ReferenceError: localStorage is not defined
This error happened while generating the page. Any console logs will be displayed in the terminal window.
Is there a proper way to make it work in a server-side rendered app?
These are the code btw if that matters.
// Coinbase START
// TypeScript
import CoinbaseWalletSDK from '#coinbase/wallet-sdk'
import Web3 from 'web3'
const APP_NAME = process.env.NAME
const APP_LOGO_URL = process.env.WEBSITE_URL + '/logo.png'
const DEFAULT_ETH_JSONRPC_URL = 'https://mainnet.infura.io/v3/' + process.env.INFURA_PROJECT_ID
const DEFAULT_CHAIN_ID = 1
// Initialize Coinbase Wallet SDK
export const coinbaseWallet = new CoinbaseWalletSDK({
appName: APP_NAME,
appLogoUrl: APP_LOGO_URL,
darkMode: false
})
// Initialize a Web3 Provider object
export const ethereum = coinbaseWallet.makeWeb3Provider(DEFAULT_ETH_JSONRPC_URL, DEFAULT_CHAIN_ID)
// Initialize a Web3 object
export const web3 = new Web3(ethereum as any)
// Coinbase END
Related call:
function connectCoinBase() {
console.log('connectCoinBase is triggered');
if (ethereum && mounted) {
setLoading(true);
ethereum.request({
method: 'eth_requestAccounts'
})
.then((res) => {
const accounts: string[] = res as string[];
if (accounts && accounts.length) {
setWalletId(accounts[0]);
setWalletType(2);
connectCrypto();
}
setLoading(false);
})
.catch(err => {
console.error('Coinbase eth_requestAccounts failed, error: ', err);
setLoading(false);
})
}
}
The error was thrown without calling this function but happens when this function is added and the page is rendered.
UPDATE: This error is related to the ScopedLocalStorage class inside the #coinbase/wallet-sdk dependency. The localStorage is not available in server-side rendering.

React Native - upload image to Firebase using #react-native-firebase/storage - No Firebase App '[DEFAULT]' has been created

I am getting the following error when uploading an image to Firebase:
Error: No Firebase App '[DEFAULT]' has been created - call firebase.initializeApp()
Here is my code:
App.js
import * as Firebase from 'firebase';
componentDidMount() {
Firebase.initializeApp(firebaseConfig);
}
Profile.js
import * as Firebase from 'firebase';
import rnFb from '#react-native-firebase/storage';
uploadImage = localUri =>
new Promise((resolve, reject) => {
const localUri2 = Platform.OS === 'ios' ? localUri.replace('file://', '') : localUri;
const fbUri = Firebase.storage().ref();
rnFb().ref(localUri2).putFile(fbUri)
.then(
() => { resolve(); }
)
.catch(
(e) => { reject(e); }
);
});
It's failing at the .putFile line.
I don't understand what the problem is because I am calling .initializeApp() in App.js
UPDATE 12/21
I added console.log(Firebase.apps.length); right before rnFb().ref(localUri2).putFile(fbUri) and the output is 1...very strange indeed.
...and if I do exactly as the error asks and call firebase.initializeApp() right before rnFb().ref(localUri2).putFile(fbUri) I get the error Error:
Firebase: Firebase App named '[DEFAULT]' already exists
Help!!
My understanding is that the Firebase SDK used internally inside #react-native-firebase is independent of the ordinary Firebase SDK from firebase.
It can be exposed using:
import firebase from '#react-native-firebase/app';
// OR
import { firebase } from '#react-native-firebase/storage';
Applying these changes (and simplifying your code), leaves you with the following:
import storage, { firebase } from '#react-native-firebase/storage';
// can possibly be somewhere else
firebase.initializeApp(firebaseConfig);
uploadImage = localUri => {
const localUri2 = Platform.OS === 'ios' ? localUri.replace('file://', '') : localUri;
return storage().ref('/path/to/upload/to').putFile(localUri2)
}
Rather than use "client initialization" using firebase.initializeApp(), you can also use "native initialization"
for Android and iOS.
Have you followed the API documentation? I can't seem to find anywhere in the docs that you need to manually call initializeApp()
I think your fbUri is wrong. The param has to be a string.
For ex:
firebase
.storage()
.ref('remote_path') // remote path where you want to store
.putFile(
'local/ok.jpeg' // local file
)
.then(successCb)
.catch(failureCb);

Firebase Storage XMLHttpRequest is not defined error with Nuxt JS

I am in need of help with my web app that is uploading an image to firebase storage then wanting to display that image in a thumbnail.
I am getting the error this.xhr_ = new XMLHTTPREQUEST is not defined
I don't have 10 rep points so it seems I can't upload my image directly.
If there was a better way to do this please let me know.
I have looked through firebase docs and many stack overflow answers but can seem to have anything that works. I have tried to globally install xmlhttprequest, also as a dependency.
As you can see I also attempted to import XmlHttpRequest but it did nothing.
The error I am getting comes from the last statement with getdownloadurl()
<script>
import XMLHTTPREQUEST from 'xmlhttprequest'
import ImageCard from '../../components/ImageCard/ImageCard'
import {db} from '../../firebase/init.js'
import {storage} from '../../firebase/init.js'
export default {
name: "explore",
components: {
ImageCard,
db,
storage,
XMLHTTPREQUEST
},
data() {
return {
cards: [],
downloadUrl: ''
}
},
created(){
//fetch data from firestore
db.collection('Assets').get()
.then(snapshot => {
snapshot.forEach( doc => {
let card = doc.data()
console.log(card)
// the card.id is adding an id property onto the let card variable
card.id = doc.id
this.cards.push(card)
console.log(this.cards)
})
})
},
created() {
const storageRef = storage.ref()
const imagesRef = storageRef.child('AshAngelPaid.jpg');
console.log('Before getting requesting download url')
imagesRef.getDownloadURL().then( (url) => {
document.querySelector('img').src = url;
console.log('got download url');
Basically, while nuxtjs is rendering your component on the server side there's no xmlhttprequest, just move .getDownloadURL and related stuff into mounted() or beforeMount() lifecycle hook.

Firebase: How to run 'HTTPS callable functions' locally using Cloud Functions shell?

I couldn't find a solution for this use case in Firebase official guides.
They are HTTPS callable functions
Want to run Functions locally using Cloud Functions shell to test
Functions save received data to Firestore
The 'auth' context information is also needed
My code as below. Thanks in advance.
Function :
exports.myFunction = functions.https.onCall((data, context) => {
const id = context.auth.uid;
const message = data.message;
admin.firestore()...
// Do something with Firestore //
});
Client call :
const message = { message: 'Hello.' };
firebase.functions().httpsCallable('myFunction')(message)
.then(result => {
// Do something //
})
.catch(error => {
// Error handler //
});
There is an api exactly for this use case, see here.
I used it in javascript(Client side) as follows -
button.addEventListener('click',()=>{
//use locally deployed function
firebase.functions().useFunctionsEmulator('http://localhost:5001');
//get function reference
const sayHello = firebase.functions().httpsCallable('sayHello');
sayHello().then(result=>{
console.log(result.data);
})
})
where sayHello() is the callable firebase function.
When the client is an android emulator/device. Use 10.0.2.2 in place of localhost.
Also the code for flutter would be like so -
CloudFunctions.instance.useFunctionsEmulator(origin: 'http://10.0.2.2:5000')
.getHttpsCallable(functionName: 'sayHello')
Cloud functions have emulators for that. Check this link it can suite your case. Its not functions shell, but for testing purposes i think it can still works for you
In newer versions of firebase, this is the way:
import firebaseApp from './firebaseConfig';
import { getFunctions, httpsCallable, connectFunctionsEmulator } from 'firebase/functions';
const functions = getFunctions(firebaseApp);
export async function post(funcName, params) {
connectFunctionsEmulator(functions, 'localhost', '5001'); // DEBUG
let func = httpsCallable(functions, funcName);
let result = await func(params);
return result.data;
}

Resources