Nuxt SPA dynamic routes based on Firebase Firestore data - firebase

So I want to have a nuxt site hosted on Netlify where there's a child route whos slug is a firebase firestore document id.
Example:
https://www.example.com/users/steve
(where "steve" is the documentid)
So when the route is hit I would need to query firebase to see if it exists, and if not I would have to return a 404. Is this even possible? I can do it easy in .net or php, but I'm very unsure of a SPA.
Specifically what should I be looking for in the docs, if I can do this?

One solution is to implement an HTTPS Cloud Function that you would call like a REST API, sending an HTTP GET request to the functions endpoint.
As explained in the doc "Used as arguments for onRequest(), the Request object gives you access to the properties of the HTTP request sent by the client".
So you Cloud Function would look like:
exports.getUser = functions.https.onRequest((req, res) => {
// get the value of the user by parsing the url
const baseUrl = req.baseUrl;
//Extract the user from baseUrl
const user = ....
//query the Firestore database
admin.firestore().collection('users').doc(user).get()
.then(doc => {
if (doc.exists) {
res.status(200).end();
} else {
res.status(404).end();
}
});
See the get started page and the video series for more info on Cloud Functions.
Note that you can connect an HTTP function to Firebase Hosting, in such a way that "requests on your Firebase Hosting site can be proxied to specific HTTP functions".

Related

Firebase emulator: see outgoing HTTP traffic

I have a Cloud Function that calls to Chargebee. In index.ts:
const chargeBee = new ChargeBee();
...
chargeBee.configure({
site,
api_key: apiKey
});
...
export const finalizeSignup = https.onCall(
async (info: SignupInfo, ctx: CallableContext) => {
const cbCmd = chargeBee.hosted_page.retrieve(info.cbHostedPage);
const callbackResolver = new Promise<any>((resolve, reject) => {
// cbCmd.request returns a Promise that seems to do nothing.
// The callback works, however.
// Resolve/reject the Promise with the callback.
void cbCmd.request((err: any, res: any) => {
if (err) {
reject(err);
}
resolve(res);
});
});
// Calling Promise.resolve subscribes to the Promise.
return Promise.resolve(callbackResolver);
}
);
I am testing this function using the Firebase emulators, started via firebase emulators:start --only functions. Chargebee is responding strangely. They require the domain of their incoming requests to be whitelisted: my first guess is that the domain being used by my locally emulated Cloud Function is not whitelisted on the Chargebee side.
How do I see outgoing HTTP information sent by my locally emulated Cloud Function?
The connection is actually HTTPS, not HTTP.
The emulators provide no functionality to intercept network traffic of any form.
For HTTP: you have to apply your own tooling to monitor the HTTP traffic (ie Wireshark).
For HTTPS: possible to monitor using Wireshark, but impossible to analyze without knowing the SSL key. And in the setup above, where a third-party library is handling the request, there is currently no way to obtain the SSL key. I entered a feature request with Firebase to gauge the interest of developing a way to define an SSL key log when starting the Functions emulator, similar to Chrome. A user only identifying themselves as 'Oscar' told me in a private email that "I've already filed a feature regarding this topic to our engineering team regarding this matter, which will be discussed internally." So that tells us that (1) Firebase is aware that the feature is currently lacking, and (2) there is no progress to report on the feature.

How to restrict a Google Cloud function to be invoked only from the Google Cloud Console?

I have a Firebase function to do some data processing, and I only want to invoke it through Google Cloud Console manually.
Just a simple function like this (using node.js):
import * as functions from 'firebase-functions'
// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript
//
export const test = functions.https.onRequest(async (req, res) => {
res.send({
query: req.query,
body: req.body,
})
})
The way I did it is to deploy the function via the firebase-cli then remove the Cloud Function Invoker role in the permission tab from GUI.
It seems to work.
But I noticed one thing, when I send the request with Postman
when you send a GET, the error is 400,
But for any request that's not a GET, you get a proper 403
My questions are:
why GET is 400 while the others are 403?
am i doing it right in terms of my requirement?
what's the correct way of doing it?
does the function get invoked while sending a request like POST?

Admin SDK + Vuejs ListAllUsers?

I have read the documentation about listing all users via admin SDK but still struggling to show users in my vue component...
the code in the documentation is:
function listAllUsers(nextPageToken) {
// List batch of users, 1000 at a time.
admin.auth().listUsers(1000, nextPageToken)
.then(function(listUsersResult) {
listUsersResult.users.forEach(function(userRecord) {
console.log('user', userRecord.toJSON());
});
if (listUsersResult.pageToken) {
// List next batch of users.
listAllUsers(listUsersResult.pageToken);
}
})
.catch(function(error) {
console.log('Error listing users:', error);
});
});
// Start listing users from the beginning, 1000 at a time.
listAllUsers();
in my component, I want to create an array that will contain all users and display them,.. The question is,.. How would I do that? is it by an axios request? and what are the steps?
As explained in the documentation "the Admin SDK supports Node.js, Java, and Python." This means that you cannot use the code in your question directly in a Vue.js component. You need to execute this code in a backend and call this backend from your Vue.js component.
One of the standard solution would be to create a Callable Cloud Function that executes this code and returns the list of users as an array. The documentation explains how to implement such a function and how to call it from your vue.js application (See here).
You could also use a "standard" HTTPS Cloud Function and call it via Axios, but using a Callable Cloud Functions brings some extra advantages as explained in the doc ("Firebase Authentication and FCM tokensare automatically included in requests, the functions.https.onCall trigger automatically deserializes the request body and validates auth tokens.", etc...).

CORS error when use cors middleware in an api built with node.js and Express

I am new to node and express. I have encountered a cors error when I am building a very simple API. I have tried several hours to solve it in different method but none of these work.
Here's my approach
const functions = require('firebase-functions');
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({ origin: true }));
app.get('/api', (req, res) => {
res.send('Hello');
});
exports.api = functions.https.onRequest(app);
and got 4 errors all about :
http://localhost:3000 is not allowed by Access-Control-Allow-Origin.
I have also tried several other some methods like this:
var allowCrossDomain = function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Cache-Control");
next();
};
app.use(allowCrossDomain);
Which gives me the same error.
I am using Firebase Cloud Function to deploy this api, because the code is so simple so I really can not figure out which part is not doing right.
CORS is always a sticky situation, but in this case, I think I might be able to help. When you run firebase deploy you should see your endpoint get deployed. If it's the first time you are deploying that function, it should print out that new function's full URL in the console, it usually looks something like this:
https://us-central1-your-project-name.cloudfunctions.net/apiEndpointName
If you've already deployed it, you can see the function's full URL in the Firebase console -> Functions -> Dashboard
That URL is the normal public API endpoint or "HTTP-trigger" for that function. If you would use Postman to make a GET request to that URL, you should expect to receive your Hello response. (Or if you visited that URL in your browser, your browser would make a GET request to that URL, you should get your Hello response there too)
The problem comes when you want to access it from your deployed/hosted website. You need to tell the hosting portion of Firebase to route any traffic for /api to your function - your Firebase hosting should not try to resolve the /api route as a normal HTML page deployed along-side the primary index.html file... instead it should direct any traffic for /api to the cloud function api
So, you need to tell Firebase to direct any traffic for /api to the cloud function, not hosting. You give Firebase commands/configuration in the firebase.json file... in this case, under a section named "rewrites" like this:
{
"hosting": {
"public": "public",
// Add the following rewrites section *within* "hosting"
"rewrites": [ {
"source": "/bigben", "function": "bigben"
} ]
}
}
Check out this documentation link where it explains all that^^
Once you've done that, redeploy everything, and now you should be able to visit /api in your browser and trigger the function. NOTE Unless you are using firebase serve you should visit the route on the deployed website, not localhost. Check out this link for more details on firebase serve.

Handling authentification to Firebase Database with Fetch in a Service Worker

I'm trying to query a Firebase database from a Service Worker using the Fetch API. However it doesn't work as expected as I can't get authenticated correctly.
Basically what I'm trying to do is from origin https://myproject.firebaseapp.com inside a Service Worker I do a call like this :
var fetchOptions = {};
fetchOptions.credentials = 'include';
var url = options.messageUrl;
var request = new Request('https://myproject.firebaseio.com/user/foobar.json', fetchOptions);
messagePromise = fetch(request).then(function(response) {
return response.json();
});
I'm getting this error :
Fetch API cannot load https://myproject.firebaseio.com/user/foobar.json. Response to preflight request doesn't pass access control check: Credentials flag is 'true', but the 'Access-Control-Allow-Credentials' header is ''. It must be 'true' to allow credentials. Origin 'https://myproject.firebaseapp.com' is therefore not allowed access.
Any idea of a way to fix it? How one should do to query/update the Firebase database from a SW?
I've read https://jakearchibald.com/2014/using-serviceworker-today/ and one of the gotcha was exactly that problem, the fact that Fetch request do not send authentification.
Ideally it would be great to be able to use the Firebase JS API inside a SW but this doesn't seem to work as well.
Firebase doesn't store authentication info as a cookie or in anything that would be sent along in the credentials, so there's no need to send them in your fetch request. Instead, you'll need to pull the token from Firebase Auth:
firebase.auth().currentUser.getToken(true).then(function(token) {
// token is the value you'll need to remember for later
});
Once you've got the token, you should be able to add it as a query parameter to the REST request e.g. ?auth={THE_TOKEN}. This will allow you to make your authenticated request in the Service Worker.

Resources