I have a firebase cloud function running locally. Its implemented like this
exports.verifyApp = functions.https.onRequest((req, res) => {
const {ref} = req.query;
// some business logic
if( ref === "123") return res.status(200).json({message: "success"});
return res.status(400).json({ error: "invalid-argument", message: "ref not provided" });
})
On frontend I am calling the cloud function like this
import {
getFunctions,
httpsCallableFromURL,
} from "firebase/functions";
const verifyClaim = httpsCallableFromURL(
getFunctions(),
"http://localhost:5001/{placeholder}/us-central1/verifyApp?ref=23"
);
verifyClaim()
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log(error.code, error.message);
});
I am not able to read/parse the custom error message being sent from the function. The .catch block only prints generic firebase error code and message i.e invalid-argument and internal. I can see the response in network tab though but .catch never seems to pick up the custom error message I am sending from cloud function.
You are mixing up Callable Cloud Functions and HTTP Cloud Functions.
You Cloud Function code corresponds to an HTTP one (functions.https.onRequest(...)) but the code in your front-end calls a Callable one (const verifyClaim = httpsCallableFromURL(...)).
You should adapt one or the other. It's difficult to advise which one to adapt with the few details shared in your answer.
Related
I have been watching a tutorial on making a Rest API for Firestore which appears to work but I cannot figure out how to catch an error.
The code below basically uses an end point to retrieve a document id from the firestore database.
The client uses javascript fetch to call the API.
I am trying to workout how to return something back to the client from the API if the document id is not there. I thought I might get a 404 status returned but I always get status 200.
This is the API code I used
app.get("/api/read/:id", (req, res) => {
(async () => {
try {
const document = db.collection("users").doc(req.params.id);
let product = await document.get();
let response = product.data();
return res.status(200).send(response);
} catch (error) {
console.log(error);
return res.status(500).send(error);
}
})();
})
I'm fairly certain that the 404 message is for the server itself not being found (though I do need to brush up on my error codes).
However, if you're looking to check to see if a document exists there's a command specifically for that demonstrated in the examples in the firebase docs
I am calling a simple firebase function from a web app I get an INTERNAL error. Can someone please suggest where I could be going wrong.
I have seen similar questions but they don't answer the issue I am facing.
I can confirm that the function has been deployed to the firebase.
By pasting the below link in the browser I get a response.
https://us-central1-cureme-dac13.cloudfunctions.net/helloWorld
index.js file has the code (Firebase cloud functions are defined in index.js)
const functions = require('firebase-functions');
exports.helloWorld = functions.https.onRequest((request, response) => {
response.send("Hello from Firebase!");
});
webApp.js has the below code (Client/Website)
var messageA = firebase.functions().httpsCallable('helloWorld');
messageA().then(function(result) {
console.log("resultFromFirebaseFunctionCall: "+result)
}).catch(function(error) {
// Getting the Error details.
var code = error.code;
var message = error.message;
var details = error.details;
// ...
console.log("error.message: "+error.message+" error.code: "+error.code+" error.details: "+error.details)
// Prints: error.message: INTERNAL error.code: internal error.details: undefined
});
You are mixing up Callable Cloud Functions and HTTPS Cloud Functions.
By doing
exports.helloWorld = functions.https.onRequest(...)
you define an HTTPS Cloud Function,
but by doing
var messageA = firebase.functions().httpsCallable('helloWorld');
messageA().then(function(result) {...});
in your client/front-end, you actually call a Callable Cloud Function.
You should either change your Cloud Function to a Callable one, or call/invoque the helloWorld HTTPS Cloud Function by sending an HTTP GET Request to the Cloud Function URL (Similarly to the way you did in your browser by "pasting the https://us-central1-cureme-dac13.cloudfunctions.net/helloWorld link in the browser").
For example, by using the Axios library, you would do:
axios.get('https://us-central1-cureme-dac13.cloudfunctions.net/helloWorld')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
I have this code to check whether an email is taken or not, it works it just throws back an error in the cloud functions logs, Here's the swift code:
let functions = Functions.functions()
functions.httpsCallable("uniqueEmail").call(email) { (result, error) in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
}
// ...
}
if let text = (result?.data as? [String: Any])?["text"] as? String {
//self.resultField.text = text
}
}
Here's the cloud function code:
import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'
admin.initializeApp()
exports.uniqueEmail = functions.https.onCall((req, res) => {
const email = req.query.email;
if (!email) {
throw new functions.https.HttpsError('invalid-argument', 'Missing email parameter');
}
admin.auth().getUserByEmail(email)
.then(function(userRecord) {
// See the UserRecord reference doc for the contents of userRecord.
console.log('Successfully fetched user data:', userRecord.toJSON());
return({taken: true}); // Returns {"taken": "true"} or {"taken": "false"}
})
.catch(function(error) {
console.log('Error fetching user data:', error);
return({taken: false}); // Returns {"taken": "true"} or {"taken": "false"}
});
});
And here's the error's I'm getting in cloud functions, I'm not sure what both mean, so could someone explain them both to me?
1.
Billing account not configured. External network is not accessible and quotas are severely limited. Configure billing account to remove these restrictions
2.
Unhandled error TypeError: Cannot read property 'email' of undefined
at exports.uniqueEmail.functions.https.onCall (/user_code/lib/index.js:7:28)
at /user_code/node_modules/firebase-functions/lib/providers/https.js:330:32
at next (native)
at /user_code/node_modules/firebase-functions/lib/providers/https.js:28:71
at __awaiter (/user_code/node_modules/firebase-functions/lib/providers/https.js:24:12)
at func (/user_code/node_modules/firebase-functions/lib/providers/https.js:294:32)
at corsHandler (/user_code/node_modules/firebase-functions/lib/providers/https.js:350:44)
at cors (/user_code/node_modules/firebase-functions/node_modules/cors/lib/index.js:188:7)
at /user_code/node_modules/firebase-functions/node_modules/cors/lib/index.js:224:17
at originCallback (/user_code/node_modules/firebase-functions/node_modules/cors/lib/index.js:214:15)
The first message is just a warning and you can ignore it unless you're trying to make outbound connections.
The second message is saying that your function code is expecting to receive an input object with a property called "query" that's an object with a property called "email". But that's not what you're passing from the client. In the client, you passed a string (I assume, as you didn't say exactly what email is in your swift code).
Futhermore, I suspect that you might be confused about what callable functions take as arguments. You're showing (req, res) as arguments, a request and a response, which is what you would normally expect from a HTTP type function. But that's not how callables work. Now might be a good time to review the documentation for callable functions. The first argument to a callable function is the data object itself passed from the client. Use that instead, don't assume that the data is coming in through a query string.
I m getting Error while invoked function.
I m using LsignInWithEmailAndPassword Method.Any Special Configuration is Require?
const functions = require('firebase-functions');
const firebase=require('firebase-admin');
firebase.initializeApp(functions.config().firebase);
exports.login = functions.https.onRequest((request, response) => {
var data = {
email : 'demo#gmail.com',
password : 'demo123'
};
var auth = null;
firebase
.auth()
.signInWithEmailAndPassword(data.email, data.password)
.then( function(user){
response.send("Authenticated successfully with payload");
// console.log("Authenticated successfully with payload:", user);
auth = user;
})
.catch(function(error){
response.send("Login Failed!");
// console.log("Login Failed!", error);
});
// response.send("Hello from Firebase!");
});
When you call firebase.auth() from the Admin SDK, you're getting an object of type Auth. As you can see from the API docs, it doesn't have a method called signInWithEmailAndPassword.
It seems you're mixing up the javascript client SDK with the Admin SDK. There's no reason to use the client SDK in Cloud Functions. It's supposed to be used in the browser only, since signing in only makes sense on the device that the user is actually using.
signInWithEmailAndPassword is only available in a browser environment. To get access to who made a particular request, you can use firebase.auth().getToken to get a JWT token, and send that along to your cloud function endpoint. Then from there you can call verifyIdToken to get the uid of whoever made the request.
My frontend, using apollo-client, throws an exception when the backend returns an error after a request.
When the node server receives a request, I check the validity of the request's token using koa middleware. If the token is valid, the request is forwarded to the next middleware. If the token is invalid, I want to return a 401 access denied error to the client. To do this, I followed Koa's error documentation located here.
The code for the error handling middleware I wrote:
function userIdentifier() {
return async (ctx, next) => {
const token = ctx.request.headers.authorization
try {
const payload = checkToken(token)
ctx.user = {
id: payload.userId,
exp: payload.exp,
iat: payload.iat,
}
} catch (error) {
ctx.user = undefined
ctx.throw(401, "access_denied")
// throw new Error("access_denied")
}
await next()
}
}
This seemingly works on the backend, but not on the frontend. When the frontend receives this error, a JavaScript runtime error occurs. I am not sure what causes this.
Note, the unexpected "a" is the same "a" found in ctx.throw(401, "access_denied"). If it were instead ctx.throw(401, "x") the frontend shows "unexpected token x" instead.
The frontend code where the errors happens:
In an attempt to fix this, I followed Apollo's error handling documentation and used apollo-link-error.
const errorLink = onError(props => {
const { graphQLErrors, networkError } = props
console.log("ON ERROR", props)
if (graphQLErrors)
graphQLErrors.map(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
)
)
if (networkError) console.log(`[Network error]: ${networkError}`)
})
Then I combine all links and create the Apollo client like this:
const link = ApolloLink.from([errorLink, authLink, httpLink])
export const client = new ApolloClient({
link,
cache: new InMemoryCache(),
})
The output of the debugging log in apollo-link-error is as follows:
Related Documents
Someone seems to be having an identical error, but a solution was not listed.
I found that the errors were handled correctly on the frontend when I began using this library on the backend: https://github.com/jeffijoe/koa-respond
Using just ctx.unauthenticated()
But I would still like to know more about how to return json/object-based errors with koa without a plugin helping