firebase cloud function redirect with express - firebase

I'm trying to automatically determine which language of the website should be user redirected to.
Setup is Firebase cloud function with ExpressJS server and Angular Universal SSR.
When preferred language is determined from request.acceptsLanguages(...) I'm trying to redirect via response.redirect('/en');.
When debugging it locally via firebase serve it redirects, but when deployed it doesn't seem to work at all, even logs from that endpoint don't show in the log list.
// All base routes are redirected to language specific
app.get('/', (req, res) => {
console.log('this is /');
if (req.acceptsLanguages('cs', 'cs-CZ', 'sk', 'sk-CZ')) {
res.redirect(`/cs`);
} else {
res.redirect(`/en`);
}
});
// All regular routes use the Universal engine
app.get('*', (req, res) => {
console.log('this is *');
res.render('index', { req });
});
export const ssr = functions.https.onRequest(app);

The problem was in the index.html being served as a static file on the / route.
I resolved it by renaming the Angular's index.html to web-index.html (any descriptive name will do).
It could also be solved by configuring the Express static file server to not serve index.html files if found for the matching routes, but that would disable serving any pages that have been pre-rendered (if you have SSR prerendering setup).

Related

What path should I use for Meteor's Webapp API?

I'm using Meteor v1.9 Webapp API to have my app listen to HTTP requests, specifically from a link to the app itself from a website, let's say example.org.
The documentation says to use
WebApp.connectHandlers.use([path], handler)
Where the [path] is defined as such:
path - an optional path field. This handler will only be called on
paths that match this string. The match has to border on a / or a ..
For example, /hello will match /hello/world and /hello.world, but not
/hello_world.
My question:
Let's say my meteor application is hosted on abc.com and the POST data being sent over to it is from example.org (where the link to abc.com is as well).
For the [path] argument mentioned above, in this case, should I have it as "/example" since example.org is where my app is listening to requests from (getting the POST data)? Or does it have to be a different format? I tried the former, but it doesn't seem to be working for it, so I'm trying to find the root of the issue.
Additional information that might be useful: I know it says 'optional' so I tried omitting it, but when I tested it out via 'meteor run' where it runs off of localhost:3000, it just yielded a blank page, with no errors and a success sent back, probably because it uses a GET request instead of POST.
My code for the webapp in my meteor application is as follows:
WebApp.connectHandlers.use("/[example]", async (req, res, next) => {
userName = req.body;
res.writeHead(200);
res.end();
});
Also technically my meteor application is built/bundled and deployed as a Node.js application on the website, but that shouldn't affect anything regarding this as far as I could tell.
That path is the path (part of the URL) on your meteor server. So in your example, for instance,
WebApp.connectHandlers.use("/example", async (req, res, next) => {
userName = req.body;
res.writeHead(200);
res.end();
});
means that you will need to send your POST requests to abc.com/example.

Firebase functions route to specific http method

I want to have a separate function for each HTTP method (GET, POST, PATCH....) - for the same URI path, for example:
// express app
...
getUser.get('/api/v1/user/:id', async (req, res) => {
...
updateUser.patch('/api/v1/user/:id', async (req, res) => {
...
exports.getUser = functions.https.onRequest(getUser);
exports.updateUser = functions.https.onRequest(updateUser);
But I don't know how to specify hosting rewrites configuration for such cases.
Is it possible to route different HTTP methods to different functions (in firebase.json file)?
According to the documentation, Firebase Hosting doesn't you specify a method for rewriting. You can only provide a URI path.
What you should probably do here is create a single express app that contains all of the methods for the single endpoint, and export that through a single named function. Express will know what to do with the method.

Is it possible to access a real API in React Storybook

I am using Storybook to test my React UI components.
However, when I get to a point where my Action makes an Axios request, I get a 404 response.
Below is the code used in a react action file:
assume the axios instantiation, thunk implementation and action definitions.
getDelayedThunkRes: () => {
return (dispatch) => {
dispatch(delayedResActions.getInitialRes());
axios.get("/test").then(success => {
console.log(success);
}).then(err => {
console.log(err);
})
}
}
localhost:8080 is my real server that I want to connect to. Obviously it should throw me an error because my storybook is running on 9009. How can I connect the two?
Note, it works for my Create React App. Create React App package gives a provision to proxy all the calls to a server using "proxy" field in package.json
Are there any similar tools in Storybook, or is Storybook supposed to be used solely with static mock data?
Alright, I found an amazing post on how to create a middleware for React storybook for APIs
https://medium.com/#wathmal/adding-a-router-middle-ware-to-react-storybook-4d2585b09fc
Please visit the link. The guy deserves the due credit.
Here is my implementation of it in ES5 (somehow Storybook middleware is unable to transpile):
create this middleware.js inside .storybook directory:
const express = require('express');
const bodyParser = require('body-parser');
const expressMiddleWare = function(router) {
router.use(bodyParser.urlencoded({extended: false}));
router.use(bodyParser.json());
router.get('/test', function(req, res) {
res.send('Hello World!');
res.end();
});
}
module.exports = expressMiddleWare
Caveat: You will have to restart Storybook every time you make a change in the middleware.
With this, I am able to make a call from my react actions.
Next, I will try to implement express HTTP proxy middleware to redirect these storybook middleware calls to my real express server.
Edit 1:
The new technique seems to be using decorators, especially with stroybook-addon-headless.
Storybook add on for setting server urls
https://github.com/ArrayKnight/storybook-addon-headless
I am yet to try

Nuxt SPA dynamic routes based on Firebase Firestore data

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".

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.

Resources