I am building a simple web app using node js express and cloud firebase functions
i have 2 endpoints,
1. first point renders the form(GET request) and
2. POST endpoint that takes the form data on submit
for some reason firebase skipping the function name in the post url(2nd end point) on form submission but it works fine on local express server
example: if form acion attribute value is "check" and firebase function name is "helloWorld"
the form submit url should be "<default firebase pefix>/helloWorld/check"
but instead the url it posting to is "<default firebase pefix>/check".
firebase function name in the url is getting skipped. which is giving me function not found in location us-central etc
another thing i observed is if i give slash as prefix to action attribute value like "action = "\check". firebase skipping the whole base url and appending from attribute value the port value
i tried a work around by setting the static absolute path (path after production) to the form action attribute.
But i want to if its a bug or am i missing something
<form action="check" method="POST"
<label for="uname"><b>Username</b></label>
<input type="text" placeholder="Enter Username" name="uname" required>
<button type="submit">Login</button>
</form>
// action = "/check" this is skipping total base url all together
const functions = require('firebase-functions');
const express = require('express')
const bodyparser = require('body-parser')
const app = express()
app.set('port',6000)
app.use(bodyparser.json())
app.use(bodyparser.urlencoded({extended:true}))
app.set('view engine', 'ejs');
app.get('/',(req,res)=>{
res.render('formfill')
})
// this below end point is supposed to get triggered on form submission.
// and it is working fine on local express server, but not on firebase functions
app.post('/check',(req,res)=>{
res.send(`you said ${req.body.uname}`)
})
exports.helloWorld = functions.https.onRequest(app);
You can't use Cloud Functions to run a web server or listen on a port. All your code that's trying to run express is not going to work. When you deploy an HTTP function, it's assigned a URL, and you use that URL as the endpoint for requests.
You should review the documentation for HTTP triggers to better understand how this works.
I solved it. i don't know if it is my mistake or lack of knowledge.
so the firebase functions url is something like this
https://us-central1-<project-id>.cloudfunctions.net/<functionname>
in the local firebase server if i go to the functions url(localhost prefix) with or without a slash at the end of the url. my root endpoint is getting consumed. which is fine.
but it is not the case in production url, a slash at end of url(after my function name) is required to load the endpoint. and any anchor tag href in the webpage should omit the prefix slash
example: action = "/check" this is not working but
action ="check/" this is working
so i just removed prefix slash in my action attribute and re deployed, now it is working.
Related
I have a simple node.js cloud function that I need the un-parsed original URL within. In the request object, we have request.url, request.originalURL but both of these seem to be parsed upstream of the function into key=parameter pairs. For example, calling the function from firebase hosting with the url https://www.example.com/index.html?var1&var2&var3 would yield an output of "/index.html?var1=&var2=&var3=" for either request attribute. I can remove the "=" characters, but it gets more complex. For example, if var1="123,456" I now have "/index.html?123%2C456=&var2=&var3=" which requires me to un-parse, and also decode the URL.
The real show stopper, is that for some reason var1 can end up after var2 and var3. I.E. "/index.html?var2&var3&var1". This doesn't happen with the local emulator, but does on the deployed version. Since I'm not using key=value pairs, I rely on the variables being in the same order. I can't change the structure without a lot of work on the front end app.
When I run the function locally with firebase emulator, i can use request.headers["x-original-url"] but this is not available when deployed to GCF.
In the express documentation, it shows that the query parser can be turned off by app.disable("query parser") or app.set("query parser", false), but neither of these have an effect on the url locally or in the cloud.
Here is a snippet to recreate the issue:
const functions = require("firebase-functions");
const express = require('express');
const app = express();
app.disable('query parser');
// also tried
// app.set('query parser', false);
app.get("*", async (req, res) => {
functions.logger.log(req.url, req.originalUrl);
return res.status(200).send(""); //
});
exports.ssr = functions.https.onRequest(app);
I think either I'm missing something in the documentation, or there is a feature to disable the express parser missing from google cloud functions.
I have a search box, in which I'm taking the user input using a form.
The form has a certain method and action.
<form action="/public/search" method="GET">
In my routes files, I want to add a controller to this route, I don't know how to access this route in my routes file.
These are all the routes that I tried and didn't work.
Also, I do want it to be a GET request and not a POST request.
const router = require('express').Router();
router.get('/public/search', getSearch);
router.get('/public/search/:id', getSearch);
router.get('/public/search?search=/:id', getSearch);
I am new to nodeJS server area, need help in understanding how to work with REST API (using express) and deploy the angular application over a singe node server and same ports.
By deploying i want to understand if user hit below url http://localhost:8000/<page_name> then the specified page should open.
And is user hit below url using get or post request
http://localhost:8000/api/<api_name> then a json or a text will be returned.
How to run both the thing over a single node server.
Lets assume, you have all your static files in the /public folder of you app. Generally spoken, if you are using express.static, you should also get your index.html because this is handled by default for each directory.
In your case, as you are using Angular, the routing is handled from the client side (SPA). You should only have one single index.html after building your Angular app. All files from your dist folder should then be placed into your /public folder. Then you need to make sure, that initial file serving provides your index.html like so:
In this example static files are served first, then your API and if nothing is found, you are getting back you index file.
const express = require('express');
const app = express();
// serve static files
app.static(__dirname + '/public'));
// serve your API
app.get('/api/welcome', function (req, res) {
res.send('Welcome');
});
// fallback routing (server side handling)
app.get(/.*/, function (req, res) {
res.sendFile(__dirname + ‘/public/index.html‘
});
app.listen(3000);
Next time please make sure, to give all necessary information in your question ;-)
With the help from Sebastian, so far I can find a solution but its not working when i am hitting URL for different pages.
const express = require('express');
const app = express();
app.use(express.static('public'))
Please provide your suggestions.
I am new to node.js. I am connecting with an api with express/node.js with ejs templating. I wanted to push some information from the browser to the api. At the moment, I can push from the command line. I understand I cannot call a node.js file from the browser directly but I was wondering when I click submit on a form if it can call node.js file and run it...what should I use, modules, routes, ajax, or any other solutions you recommend? I appreciate the help.
Well, it's a strange question. Your Node application needs to either listen for HTTP requests or WebSocket connections (possibly using some abstraction like Socket.io that can provide fallbacks where WebSocket is not available) and handle the requests or messages sent on the socket. In those handlers you can do whatever you need. This is just a basic principle of client/server architecture.
Now, to choose what technology is best suited for your needs it all depends on how often you need to make that communication, whether or not you need realtime communication, how much data do you need to pass around, if you need to support serving data initiated by the server or only by the client etc.
To answer you question - yes, you can submit a form and make it execute some code in your Node application. This is exactly how forms work - they make a connection, usually GET with data in the query string or POST with data in the body (both can easily be read by Node) and then your handler on the backend handles the request, does whatever it needs and sends a response.
Consider this simple example using express and body-parser:
const app = require('express')();
const { urlencoded } = require('body-parser');
app.use(urlencoded({ extended: true }));
app.use('/', (req, res) => {
const { method, path } = req;
const { x } = req.body;
console.log(`Client request: ${method} ${path} (x = ${x})`);
res.end(`
<!doctype html>
<html>
<head>
<title>Form handling example</title>
</head>
<body>
<p>x = ${x}</p>
<form method="POST" action="/">
Enter x: <input type="text" name="x">
<input type="submit" value="Submit">
</form>
</body>
</html>
`);
});
app.listen(4447, () => console.log('Listening on http://localhost:4447/'));
Create a new directory, save this code as server.js, run:
npm init -y
npm install express body-parser -S
node server.js
and access the printed URL in the browser.
When you click the submit button you'll see what will happen in the Node app.
Your node app will have a route set up which accepts GET or POST requests. Then it does some logic and returns some data in a response.
Your web page will send the form to your node route as GET or POST via an AJAX call, and likewise it will receive a response from the AJAX call. Then you can take this response and use it locally in the webpage however you like.
Ok, so I'm just starting to learn Vue.js, and man, it's so hard to do things that are very simple when just using EJS for example. I'm close to abandon Vue for my current project, since I just don't know how to pass res.locals.something from Express server to Vue frontend. By the way, it's Passport.js thing - when authenticated, user should be redirected, but I have to pass the info whether user has logged in or not to Vue (res.locals.isLogged = req.isAuthenticated();), and that seems impossible with my current (close to 0) Vue.js skills... The only solution I found was using ajax (axios was my choice) request on the client side, targeting /login/facebook route on the server, and then I could pass the response from Express to Vue, but it cannot work because of the damned CORS issue. So, I cannot use ajax to retrieve the data from Express, and Express and Vue are not natively connected like Express and EJS or Pug for example.
In short - does anyone know of a simple way to pass Express variable to Vue, not including Vue SSR, Express-vue module etc.?
P.S. I'm not using Webpack or anything similar (so, no .vue files etc.) - just a simple index.html file with Vue loaded from CDN.
Ok, one thing that crossed my mind as dirty workaround was using .ejs instead of .html extension, so I could pass the variable to ejs, but I thought it won't work. What I did was just renaming my index.html to index.ejs, passing res.locals.isLogged to ejs template and both Vue and ejs rendered parts of the app are working together, somehow...
So, this is the dirty (sort of) solution...
The question has already been answered but I'm not familiar with .ejs and couldn't follow the solution. For those like me, what I did was :
Sent the data using res.locals or res.render('file.pug', data)
Set the data received as a html data attribute to a tag ( ex : p(id="myParagraph" data-myData= data)
Set the state of the Vuex store using
mounted : function () {
this.$store.state.myData = document.getElementById("myParagraph").getAttribute("data-myData");
}
The same can be used to set the data property of the vue root instance.
From here on you can use the data whenever needed and still retain reactivity.
You're on the right track using res.locals. To get access to the variable in the JS that's in the view, you have to wrap the value in a string: console.log('#{isLogged}'). See example below
app.js
const express = require('express')
const app = express()
app.set('view engine', 'pug')
app.use((req, res, next) => {
res.locals.isLogged = false
next()
})
app.get('/', (req, res) => {
res.render('index')
})
app.listen(3000, () => {
console.log('listening on 3000')
})
views/index.pug
doctype html
html
head
title= title
body
h1= text
script.
console.log('#{isLogged}') // false