React Native how to send AsyncStorage data to MongoDB database? - javascript

I am not able to transfer user input which is stored in a AsyncStorage to my MongoDB database
I have a MongoDB database which I start from the terminal. The console output is the following so there should not be any problems:
Server started on PORT 5000
MongoDB Connected cluster0-shard-00-02.mhqqx.mongodb.net
After this I open my React Native app with expo go and go to my register screen where a new user profile should be created. I store every required user input (name, email, etc.) in a AsyncStorage in JSON format like this:
const nameString = JSON.stringify(name)
const emailString = JSON.stringify(email)
AsyncStorage.setItem('nameInput', nameString);
AsyncStorage.setItem('emailInput', emailString);
setName('');
setEmail('');
When I print the values of the AsyncStorages in the console, there is no error and the data is displayed correctly. So the user inputs are stored in the AsyncStorages.
But after this I try to transfer the AsyncStorage data to my MongoDB database by triggering the following function with a button onPress call:
const submitHandler = async (e) => {
if(password !==confirmpassword) {
setMessage('Passwords do not match')
} else {
setMessage(null)
try {
const config = {
headers: {
"Content-type": "application/json",
},
};
setLoading(true);
const { data } = await axios.post(
"/api/users",
{name, email, password},
config
);
setLoading(false);
} catch (error) {
setError(error.response.data.message);
}
}
console.log(email);
};
When I check the database, no new information is displayed in my database. The database is functional and the route which is defined should be correct. What could be the problem?
I am also able to create a new user from Postman like this:
I have tried to search some answers for this problem for a while now but without success. Help would be much appreciated!

You can do something like
await axios.post("/api/users",
{name, email, password},config)
.then(res=> console.log(res)
.catch(err => console.log("api error", err)
And see what you get in your corresponding terminal.
Note
Your API endpoint(api/users) is not valid. Add the same URL from Postman which you're using.

Related

How can I locally test cloud function invocation from third-party in Firebase?

I am developing an API for a third-party application not related to Firebase. This API consist of cloud functions to create and add users to database, retrieve user information and so on. These functions are created using the admin SDK. Example of a function that adds a user looks like this:
export const getUser = functions.https.onRequest(async (req, res) => {
res.set('Access-Control-Allow-Origin', '*');
if (req.method === 'OPTIONS') {
res.set('Access-Control-Allow-Headers', 'Content-Type');
res.set('Access-Control-Max-Age', '3600');
res.status(204).send('');
} else {
const utils = ethers.utils;
const method = req.method;
const body = req.body;
const address = body.address;
const userAddress = utils.getAddress(address);
let logging = "received address: " + address + " checksum address: " + userAddress;
let success = false;
const db = admin.firestore();
const collectionRef = db.collection('users');
// Count all matching documents
const query = collectionRef.where("userAddress", "==", userAddress);
const snapshot = await query.get();
// If no documents match, there is no matching user
console.log(snapshot.docs.length);
if (snapshot.docs.length != 1) {
logging += "User does not exist in database.";
res.send({success: success, logging: logging});
return;
}
const data = snapshot.docs[0].data();
if (data != undefined) {
const createdAt = data.createdAt;
const emailAddress = data.emailAddress;
const userAddress = data.userAddress;
const updatedAt = data.updatedAt;
const userName = data.userName;
success = true;
res.send({success: success, createdAt: createdAt, emailAddress: emailAddress, userAddress: userAddress, updatedAt: updatedAt, userName: userName, logging: logging});
}
}
});
NOTE: These functions are NOT going to be called by the third-party application users, only by the third-party application itself.
I am pretty new at programming so I understand that this may not be the best way to code this functionality and I'm greatful for any tips you might have here as well. Anyway, back to my question. I'm trying to mimic the way that my customer is going to invoke these functions. So to test it, I'm using the following code:
function runGetUser() {
// test values
const address = 'myMetaMaskWalletAddress';
axios({
method: 'POST',
url: 'http://127.0.0.1:5001/cloud-functions/us-central1/user-getUser',
data: { "address": address },
}).then((response) => {
console.log(response.data);
}).catch((error) => {
console.log(error);
});
};
This works fine. However, I do not want anyone to be able to invoke these functions when I actually deploy them later. So I have been reading Firebase docs and googling on how to setup proper authentication and authorization measures. What I have found is setting up a service account and using gcloud CLI to download credentials and then invoke the functions with these credentials set. Is there not a way that I could configure this so that I query my API for an authorization token (from the file where the axios request is) that I then put in the axios request and then invoke the function with this? How do I do this in that case? Right now also, since I'm testing locally, on the "cloud function server-side" as you can see in my cloud function example, I'm allowing all requests. How do I filter here so that only the axios request with the proper authorization token/(header?) is authorized to invoke this function?
Thank you for taking the time to read this. Best regards,
Aliz
I tried following the instructions on this page: https://cloud.google.com/functions/docs/securing/authenticating#gcloud where I tried to just invoke the functions from the Gcloud CLI. I followed the instructions and ran the command "gcloud auth login --update-adc", and got the response: "Application default credentials (ADC) were updated." Then I tried to invoke a function I have "helloWorld" to just see that it works with the following command: curl -H "Authorization: bearer $(gcloud auth print-identity-token)" \http://127.0.0.1:5001/cloud-functions/us-central1/helloWorld", and I got the following response: "curl: (3) URL using bad/illegal format or missing URL". So I don't know what to do more.

data not writing to firestore database

The code below is a component within nextjs with the purpose of writing data to a firestore database after the user clicks a button.
Firebase isn't writing my data to the firestore database, however the alert within my callback (that is after the supposed datadump) works. i tried checking over my process.env file to see if that's where the problem was, but that wasn't the issue.
heres my write file
import firebase from 'firebase/app'
import 'firebase/firestore'
const WriteToCloudFirestore = () => {
const sendData = () => {
try {
//send data
firebase
.firestore()
.collection('myCollection')
.doc('my_document')
.set({
string_data: 'string',
more_data: 123
})
.then(alert('data sent to firestore'))
}
catch(e) {
console.log(e)
alert(e)
}
}
return (
<>
<button onClick={sendData}>send data to cloud firestore</button>
</>
)
}
export default WriteToCloudFirestore
if you are in need of anymore files I can add them, but as far as I'm aware firebase has been initalized on my app. I looked through some other questions on this forum and was able to find a very similar problem that had to do with the data returning null - but I don't see how that's my issue because I am placing data in my .set portion of the firestore code.
Javascipt alerts are synchronous that means it'll block any code execution unless the alert is dismissed. The moment you dismiss the alert your data will pop up in Firestore. Therefore, you should handle the promise returned by Firestore set method first and then show the alert.
firebase
.firestore()
.collection("myCollection")
.doc("my_document")
.set({
string_data: "string",
more_data: 123,
})
.then(() => {
console.log("Data addded")
alert("data sent to firestore")
})
.catch((e) => console.log(e));
Alternatively you can use async-await syntax:
const sendData = async () => {
console.log("Sending Data");
try {
await firestore.collection("myCollection").doc("my_document").set({
string_data: "string",
more_data: 123,
})
alert("Data added to Firestore")
} catch (e) {
console.log(e)
}
}
You can read more about that behaviour in this blog.

Authenticated requests after sign in with React Query and NextAuth

I'm having troubled sending an authenticated request to my API immediately after signing in to my Nextjs app using NextAuth. The request that is sent after signing in returns data for and unauthenticated user.
I believe the issue is that React Query is using a previous version of the query function with an undefined jwt (which means its unauthenticated). It makes sense because the query key is not changing so React Query does not think it's a new query, but, I was under the impression that signing in would cause loading to be set to true temporarily then back to false, which would cause React Query to send a fresh request.
I've tried invalidating all the queries in the app using queryClient, but that did not work. I've also used React Query Devtools to invalidate this specific query after signing in but it still returns the unauthenticated request. Only after refreshing the page does it actually send the authenticated request.
// useGetHome.js
const useGetHome = () => {
const [session, loading] = useSession();
console.log(`session?.jwt: ${session?.jwt}`);
return useQuery(
'home',
() => fetcher(`/home`, session?.jwt),
{
enabled: !loading,
},
);
}
// fetcher
const fetcher = (url, token) => {
console.log(`token: ${token}`);
let opts = {};
if (token) {
opts = {
headers: {
Authorization: `Bearer ${token}`,
},
};
}
const res = await fetch(`${process.env.NEXT_PUBLIC_BACKEND_URL}${url}`, opts);
if (!res.ok) {
const error = await res.json();
throw new Error(error.message);
}
return res.json();
}
// Home.js
const Home = () => {
const { data: home_data, isLoading, error } = useGetHome();
...
return(
...
)
}
Attached is the console immediately after signing in. You can see the the session object contains the jwt after signing in, but in the fetcher function it is undefined.
console after signing in
Any help here is appreciated. Is there a better way to handle authenticated requests using React Query and NextAuth? Thank you!
I have tried a similar situation here and struggled the same thing but the enabled property worked fine for me and it is good to go right now.
https://github.com/maxtsh/music
Just check my repo to see how it works, that might help.

How to validate firebase user current password

I am creating a form, in react-redux to change user password. I am wondering how can I validate the user current password in order to change to new one.
in my form I have 2 fields: old password, new password.
this is my action:
const { currentUser } = auth
currentUser.updatePassword(newPassword)
.then(
success => {
dispatch({
type: CHANGE_USER_PASSWORD_SUCCESS,
payload: currentUser
})
},
error => {
dispatch({
type: CHANGE_USER_PASSWORD_FAIL,
error: error.message
})
}
)
I am wondering, how to validate the old password in firebase? Should I use signInWithEmailAndPassword()? Or, is there a function to validate the current password without calling the signIn again, since my user is already logged in?
Thanks
Well, I believe you want the user to enter the old password just to verify whether it's the actual owner of the account or not.
Firebase handles this situation very well, you just need to call the updatePassword method on the user object and pass in the new password.
const changePassword = async newPassword => {
const user = firebase.auth().currentUser;
try {
await user.updatePassword(newPassword)
console.log('Password Updated!')
} catch (err) {
console.log(err)
}
}
If it's been quite a while that the user last logged in then firebase will return back an error -
"This operation is sensitive and requires recent authentication. Log in before retrying this request."
Thus, you don't really need to check the old password as firebase does it for you.
But if you just want to do it in one go, without having the user to log in again.
There's a way for that as well.
There is a method on user object reauthenticateAndRetrieveDataWithCredential you just need to pass in a cred object(email and password) and it refreshes the auth token.
const reauthenticate = currentPassword => {
const user = firebase.auth().currentUser;
const cred = firebase.auth.EmailAuthProvider.credential(
user.email, currentPassword);
return user.reauthenticateAndRetrieveDataWithCredential(cred);
}
In your particular case, you can have something like this
const changePassword = async (oldPassword, newPassword) => {
const user = firebase.auth().currentUser
try {
// reauthenticating
await this.reauthenticate(oldPassword)
// updating password
await user.updatePassword(newPassword)
} catch(err){
console.log(err)
}
}
Learn more about firebase reauth - https://firebase.google.com/docs/auth/web/manage-users#re-authenticate_a_user
Hope it helps

Cannot parse Firebase url. Please use https://<YOUR FIREBASE>.firebaseio.com

While i click on the login button i get this error :
[19:49:11] [2018-12-25T20:49:57.389Z] #firebase/database:, FIREBASE
FATAL ERROR: Cannot parse Firebase url. Please use https://<YOUR
FIREBASE>.firebaseio.com
- node_modules/#firebase/logger/dist/index.cjs.js:69:32 in
defaultLogHandler
- node_modules/#firebase/logger/dist/index.cjs.js:159:31 in error
- node_modules/#firebase/database/dist/index.cjs.js:333:20 in fatal
- node_modules/#firebase/database/dist/index.cjs.js:1256:14 in
parseRepoInfo
- node_modules/#firebase/database/dist/index.cjs.js:15103:38 in
refFromURL
* src/modules/auth/api.js:24:24 in getUser
* src/modules/auth/api.js:19:32 in <unknown>
- node_modules/#firebase/auth/dist/auth.js:17:105 in <unknown>
- node_modules/#firebase/auth/dist/auth.js:20:199 in Fb
- ... 13 more stack frames from framework internals
I copied and pasted the config stuff directly from Firebase, so it should be correct, but I get this error anyway. What could be causing this? Is there any way the URL I'm copying from my database could be wrong somehow?
As you you can see in the error shown are in my file api.js in
.then((user) => getUser(user, callback))
and in
database.refFromURL('users').child(user.uid).once('value')
So here is my code from api.js is like this :
import { auth, database, provider } from "../../config/firebase";
export function register(data, callback) {
const { email, password } = data;
auth.createUserWithEmailAndPassword(email, password)
.then((user) => callback(true, user, null))
.catch((error) => callback(false, null, error));
}
export function createUser (user, callback) {
database.refFromURL('users').child(user.uid).update({ ...user })
.then(() => callback(true, null, null))
.catch((error) => callback(false, null, {message: error}));
}
export function login(data, callback) {
const { email, password } = data;
auth.signInWithEmailAndPassword(email, password)
.then((user) => getUser(user, callback))
.catch((error) => callback(false, null, error));
}
export function getUser(user, callback) {
database.refFromURL('users').child(user.uid).once('value')
.then(function(snapshot) {
const exists = (snapshot.val() !== null);
if (exists) user = snapshot.val();
const data = { exists, user }
callback(true, data, null);
})
.catch(error => callback(false, null, error));
}
can anyone please help where i missed up
i used
database.ref(`users/`+user.uid).once('value')
instead of
database.refFromURL('users').child(user.uid).once('value')
and it works fine for me now.
Please go through this documentation and update to new modular type or if you want to use old structure then, update to
<script src="https://www.gstatic.com/firebasejs/8.5.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.5.0/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.5.0/firebase-database.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.5.0/firebase-storage.js"></script>
update all to version 8.5.0. Will work flawless
The refFromURL method expects a fully qualified URL to the database. So something starting with https://<YOUR
FIREBASE>.firebaseio.com as the error message shows.
You're trying to access a path within the configured database, in which case you should use ref(...) instead:
database.ref('users').child(user.uid).once('value')
I think there are mainly two types of realtime db urls , one ends with ".firebaseio.com" which is for US and other like EU and asia have url which ends with "firebasedatabase.app"
"Please use https://.firebaseio.com", this error comes at line when u call firebase.database(), It can happen that firebase library or module you are using are of old versions which can only make call for db whose url ends with firebaseio.com,
so make sure to update it,
or you can just change the region of your realtime database to US region.

Categories

Resources