Express app using firebase functions - node.js

Im trying to run an Express app into firebase, i'm following the steps of this official video:
Node.js apps on Firebase hosting crash course
My Express app is actually running on this URL
http://localhost:5001/my-app/us-central1/app/test
But on the video, the demostration is running on this url
http://localhost:5000/test
So, i'm really confused about this, i'been made everything as the tutorial shows
this is my code on functions/index.js
const functions = require('firebase-functions');
const express = require('express')
const app = express()
app.get('/test', (req, res) => {
res.send(`Well if i'm reading this the app is working`)
})
exports.app = functions.https.onRequest(app)
And this is firebase.json
{
"hosting": {
"public": "public",
"rewrite":[{
"source": "/test",
"function": "app"
}],
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}
What i'm doing wrong? if i enter to localhost:5000 i just get the public static index.html, i just want to control the app by myself.
I hope you can give me a little help to get documented, thanks!

The issue here is that Firebase Hosting will serve static content that matches any paths before using any rewrites. If you want to control a path with Cloud Functions, you will have to make sure that there is no static content that matches the path.
For single page apps in particular, it's critical to remove index.html, as that will always be served as static content.

Related

Rerouting Firebase Hosting to Express Cloud Functions

I can't seem to configure routes to connect firebase hosting to my cloud function express app. I tried to setup as shown here but the behaviour seems to be different. I can't seem to figure out what I am doing wrong. Please send help, I'm going insane.
index.js
const functions = require("firebase-functions");
const app = require('./app');
exports.api = functions.https.onRequest(app);
app.js
const app = express();
// ...
app.use(cors());
app.use('/params', paramsRoutes);
module.exports = app;
firebase.json
{
"hosting": {
// ...
"rewrites": [
{
"source": "/api/**",
"function": "api"
},
// ...
]
}
}
There is appropriate documentation that lists your requirement of hosting the Cloud Functions in Firebase Hosting using a custom domain.
Make sure that you have the latest version of the Firebase CLI and
that you've initialized Firebase Hosting.
Initialize Cloud Functions by running the following command from the
root of your project directory: firebase init functions
Also as per documentationwe can use rewrites to serve requests for a specific firebase hosting URL to a function. To do that you need to use "/api". You don't have to add the entire URL because you are redirecting from firebase hosting. So, when you add "/api" you are indicating to redirect requests going to "PROJECT_ID.web.app/api and PROJECT_ID.firebaseapp.com/api" to the function you specified.
If you want redirect every single URL to your host to an express app in Cloud Functions, you will need to do the following:
Make sure there is no index.html in your public hosting folder
(otherwise it will always be served with the path /).
Your Express routes need to exactly match the incoming URL, not just
the wildcard part.
You can read more in the docs or follow this medium post for more details.
Check these links for similar implementation:
How to write redirect rules for Firebase hosting and express
How to redirect all server requests to a function in firebase

How do I add vue.js client to an existing node.js api?

I have a node.js API with several endpoints that is working great. I have created a separate vue.js client app to manipulate data with the API I created. This is also working great. I have run into an issue where I need these apps to be running on the same port so a third party proxy system can access both these apps simultaneously.
I have seen a way to do this by copying the dist directory over to the node server but since I need this for a production env I need an alternative that dynamically builds the front end when building the node API as well.
Is there a production level alternative to adding a client app to run on an existing node server? Any recommendations or help would be greatly appreciated!
Update: I've added this to my router file and have client and server in one project
const path = require('path');
const router = express.Router();
router.use(express.static(path.join(__dirname, '../client/dist')));
//production mode
if(process.env.NODE_ENV === 'production') {
router.use(express.static(path.join(__dirname, '../client/dist')));
//
router.get('/test', (req, res) => {
res.sendFile(path.join(__dirname = '../client/dist/index.html'));
})
}
//build mode
router.get('/test', (req, res) => {
res.sendFile(path.join(__dirname+'../client/dist/index.html'));
})
You can expose the dist directory built with vue-cli using a express static route. This directory should have your built assets along with index.html
app.use('/app', express.static(path.join(__dirname, '../client/dist'));
However, now since your application is not at the root directory you have to add a base url to your vue.config.js. Rebuild the app after this.
module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? '/app/' : '',
...
...
...
}
Now your vue app should be available at
/app/index.html

How to fix needing to reload my api in nuxt every time i change my api?

I connected an express api to the nuxt servermiddleware: ['~/api/index'] in the nuxt.config.js file. but if i'm dev building my api, i don't want to reload the dev server manually every single time i change something in the code (that costs a lot of time). It looks like the api runs independent from the nuxt.js website. if the website reloads, the api won't and the changes will not show. Is there a way that the api reloads when the website reloads?
my code in the index.js of the api is this:
const express = require('express')
const app = express()
const bodyParser = require("body-parser")
app.use(bodyParser.json())
// Require API routes
const company = require('./routes/company')
// Import API Routes
app.use('/company', company)
// Export the server middleware
module.exports = {
path: '/api',
handler: app
}
i hope its more clear now.
In the components folder edit your config to be like
{
// this avoids reloading all components every time you run the app
components: false
}

Getting started with parse server and node.js basics

I have installed bitnami parse server from the AWS market place to provide the backend for an iOS app. In the iOS app the API is configured under http://myURL.com/parse and when I go to what I thought would be the homepage, http://myURL.com, it instead redirects me to the parse dashboard located at http://myURL.com/apps. I would like to have http://myURL.com serve a homepage for my app instead of redirecting to the parse dashboard so that a web application can be constructed that shares the same data the app uses. This is my first project using node.js so I am hoping someone could point me in the right direction on a couple of topics. My previous web application work was always on a LAMP stack so I am curious:
Am I correct to assume that the parse backend that iOS uses can also be the backend for a web application accessed through a browser?
When I analyze the code in server.js at /home/bitnami/apps/parse/htdocs I don't see a function that is redirecting to myURL.com/apps, is there a different area I should be focussed on to understand how myURL.com gets redirected to the apps folder?
I noticed that a folder exists at /home/binami/apps/rockmongo with installation instructions of php scripts, can my AWS instance run php AND the node.js or will installing a LAMP stack interfere with the node.js stack?
I am sure there is some great documentation and/or tutorials on this, can you help me get started by providing the correct way to phrase google searches or even better any links to tutorials themselves?
For context my iOS lets users log on and lets them upload images to parse server classes, I simply want to let the users log on and upload an image from a web browser using the same parse server which has the user/file classes.
For Reference below is the server.js which appears to somehow be directing requests from myURL.com to myURL.com/apps:
require('dotenv').config();
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var app = express();
// Specify the connection string for your mongodb database
// and the location to your Parse cloud code
var api = new ParseServer({
databaseURI: "mongodb://root:9dh********#127.0.0.1:27017/bitnami_parse",
cloud: "./node_modules/parse-server/lib/cloud-code/Parse.Cloud.js",
appId: "19defd7********",
masterKey: "cd8********",
fileKey: "3bce6********",
serverURL: "http://54.**.**.**:80/parse",
filesAdapter: {
"module": "#parse/s3-files-adapter",
"options": {
"bucket": process.env.S3_BUCKET,
}
},
});
// Serve the Parse API on the /parse URL prefix
app.use('/parse', api);
var port = 1337;
app.listen(port, function() {
console.log('parse-server running on port ' + port);
});
//Parse Dashboard
var ParseDashboard = require('parse-dashboard');
var dashboard = new ParseDashboard({
apps: [
{
appName: "My Bitnami Parse API",
appId: "19defd7********",
masterKey: "cd8d*******",
fileKey: "3bce6********",
production: true,
serverURL: "http://54.**.**.**:80/parse"
}
],
users: [
{
user: process.env.ADMIN_USER,
pass: process.env.ADMIN_PASSWORD
}
], useEncryptedPasswords: true
});
var allowInsecureHTTP = true;
// Serve the Parse Dashboard on the /parsedashboard URL prefix
app.use('/', dashboard);
var portdash = 4040;
app.listen(portdash, function() {
console.log('parse-dashboard running on port ' + portdash);
});
Mount point for Parse Dashboard is definded in this line:
app.use('/', dashboard);
When you want to use a separate mount point for dashboard you can do this:
app.use('/dashboard', dashboard);
After changing if you hit http://myURL.com/dashboard it will load the dashboard in /dashboard/apps. '/apps' endpoint is handled by parse dashboard itself.
Now if you want to load your website in root route (/) or the http://myURL.com, you need to create another route (assuming you want to serve a static site for now)
app.use('/public', express.static(path.join(__dirname, '/public'), {
etag: true
}));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, '/public/index.html'));
});
To serve a static site you need to create a folder from where you will server the static site. In this case, I created a folder named as public and place all of my html,css,js there. Now I need to specify the static folder in express. That's what I did in the first line. After that, I simply serve the index.html by creating a 'GET' route.
You can do a lot of other things too like creating APIs or serve a dynamic website as well as using parse server. But to do that you must understand express framework with nodejs first.
Update:
Parse API and Dashboard are two separate things. You can run only parse-server without dashboard and vice-versa. In your code, you mount the parse-server in /parse endpoint. Look at this line
app.use('/parse', api);
So now the parse-server is available in /parse endpoint. You can change it to anything. Make separate endpoints for both parse-server and dashboard.

Heroku node + react app: anchor tag auth request unhandled

I'm building a node + express server, with create-react-app to the frontend.
I used passportjs for auth routes handling, and all the stuff totally working on localhost ( backend on port 5000 and frontend on port 3000, with a proxy ).
When I deploy to Heroku, seems like the server can't recognize my auth routes and so heroku serve up static index.html.
If I test my APIs with Postman all seems to work ( I can see the html page for google oauth ), but with an anchor tag in my react app or manually writing the endpoint in the url, I can see only the same page reloading.
My server index.js:
const express = require('express')
const passport = require('passport')
const mongoose = require('mongoose')
const path = require('path')
// KEYS
const keys = require('./config/keys')
// MONGOOSE MODELS
require('./models/User')
mongoose.connect(keys.mongoURI)
// PASSPORT SETUP
require('./config/passport')
// CREATE THE SERVER
const app = express()
// EXTERNAL MIDDLEWARES
require('./middlewares/external')(app)
// ROUTE HANDLERS
require('./routes/authRoutes')(app)
// PRODUCTION SETUP
if (process.env.NODE_ENV === 'production') {
// express serve up production assets ( main.js, main.css )
app.use(express.static('client/build'))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
})
}
// START THE SERVER
const PORT = process.env.PORT || 5000
app.listen(PORT)
Flow:
LOCALHOST:
react app starts -> I click 'Google Login' -> GET request to "/auth/google" -> google oauth flow -> redirect to "/" and my react app reappears, the user is logged in.
HEROKU:
react app on my-app.herokuapp.com/ -> click on "Google Login" -> the page reloads, nothing happens. the user is not logged in.
Please guys, help me.
Thanks
This is a result of the service worker being installed by default to make your app a Progressive Web App
To determine if this is an issue for you, test your heroku production mode app in incognito mode. The request for /auth/google should now reach the server and behave as it does in development.
Once you determine it is an issue, you can remove the
import registerServiceWorker from "./registerServiceWorker";
from your /client/src/index.js file.
You browser cache may already contain an installed service worker so you may have to
clear browser cache on a user browsers
uninstall the server worker programmatically
import { unregister } from './registerServiceWorker';
....
unregister();
I had the same issues with same symptoms exactly.
For me the cause was a typo in the keys: in server/config/prod.js I had a line reading cookieKey: process.env.COOKIE_KEY but in Heroku Config Variables that variable was named cookieKey. Renaming it to COOKIE_KEY inside Heroku solved the issue.
If you've followed the Stephen Grider tutorial one thing I'm wondering: Is your passport.js file in config or services? I see you've written in index.js: require('./config/passport')
whereas mine in index.js is require('./services/passport')
may not be your solution to the google oauth flow hanging in production but may help.

Resources