I've been working on this seemingly simple problem for about a week now and feel like there is conflicting information and am hoping someone can give shed some light for me. I'm trying to use Parse Hosting for a marketing site with bootstrap, just HTML and CSS with a little JS; and Cloud Code to do some simple server side tasks like charging a card via Stripe. Everything in the documentation makes it seem this is easily doable, but the documentation also seems to lead me to believe certain methods aren't.
For example, this video shows a Stripe engineer building exactly what I want. However, it's not abundantly clear that he is using pure HTML and CSS for the front end instead of an Express templating engine (which I am not using) - http://blog.parse.com/videos/parse-developer-day-2013-a-new-kind-of-checkout/
This post says Parse Hosting and Express now work hand in hand, GREAT!
http://blog.parse.com/announcements/building-parse-web-apps-with-the-express-web-framework/
But the documentation (JS > Cloud Hosting > Dynamic Websites) says you have to delete index.html >> "If you choose to use Express or Node.js, you'll first need to delete public/index.html so that requests can get through to your custom handler functions."
I want to have a single page website hosted at public/index.html that uses Stripe Checkout v3 to create a token then pass that to Parse for a quick execution of the charge, but again, every which way I try has been unsuccessful so far.
In addition, I'm thinking Parse Hosting of pure HTML/CSS won't work with Cloud Code the way I want because a simple call of /hello below returns nothing.
Here's my code:
//public
//index.html
<form action="/charge" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="pk_test_zippitydoo"
data-image="http://image.jpg"
data-name="Thing"
data-description="Shut up and take my money"
data-amount="4000">
</script>
</form>
//cloud
//main.js
var express = require('express');
var app = express();
var Stripe = require('stripe');
Stripe.initialize('sk_test_blahblahblah');
app.get('/hello', function(req, res) {
res.send('hello world');
});
app.post('/charge', function(req, res) {
res.send('Charge Attempt');
token_id = req.body.stripe_token
Stripe.Tokens.retrieve(token_id).then(function(token) {
return Stripe.Charges.create({
amount: 1000,
currency: "usd",
source: token_id
});
});
});
What you need is for express to serve your HTML. To do this, register a static resources directory. In your main.js, after you instantiate your app with var app = express(), do this:
app.use(express.static('public'));
Express should then treat your /public/index.html file as the directory index by default, and your app will serve any other files under /public. More info: http://expressjs.com/4x/api.html#express.static
There are several things I did wrong here. I'll explain my mistakes, then you can compare the below code that works with the above code in the question that doesn't.
1) I wasn't parsing the data I was receiving (see underneath // App configuration section)
2) The JSON that is passed needs to be parsed using CamelCase (stripeToken not stripe_token)
3) The charge is set as a variable, not returned (var = charge instead of return charge). Return may work, I didn't test it however.
4) It is imperative that you include the app.listen(); in order to connect to the public folder from the cloud folder
//cloud
//main.js
var express = require('express');
var Stripe = require('stripe');
Stripe.initialize('sk_test_blahblahblah');
var app = express();
// App configuration section
app.use(express.bodyParser()); // Middleware for reading request body
app.post('/charge', function(req, res) {
var stripeToken = req.body.stripeToken;
var stripeEmail = req.body.stripeEmail;
res.send('Charging your card...');
var charge = Stripe.Charges.create({
amount: price,
currency: "usd",
source: stripeToken,
receipt_email: stripeEmail
}, function(err, charge) {
if (err && err.type === 'StripeCardError') {
res.send('The card has been declined. Please check your card and try again.');
}
});
});
// Attach the Express app to your Cloud Code
app.listen();
Related
I'm trying to pass through a view as well as a json file so that I can manipulate it within the view.`
var express = require('express');
var router = express.Router();
var data = require('../monsters.json');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index');
res.json(data);
});
module.exports = router;
`
It passes through the render of the index.ejs view but in the console there is no indication of a json file with it. Nor is there any way to manipulate the file and read it. I'm not sure if I'm just being silly and the method for passing it through doesn't exist.
EDIT: I've now tried this and am pretty sure its being passed through, is there anyway I can verify that the file has been passed through? `
router.get('/', function(req, res, next) {
res.render('index');
res.header("Content-Type",'application/json');
res.sendFile(path.join(__dirname, 'monsters.json'));
});
`
You can't send multiple responses. You get one response per request.
If the file you want to include is JSON, then you can embed it into a <script> tag in your HTML page using your template engine so everything would be in your HTML page and it can be the one response. Then, the JSON will get parsed automatically into a Javascript object that is available to your page's Javascript.
The other alternative is that you have the Javascript in the page make it's own Ajax call to your server to fetch the desired JSON in a separate http request. You would then make a route on your web server for handling that Ajax request and sending back the desired file.
As far as I am aware, you can't respond twice - you can however seemingly provide a callback to res.render(view, locals, callback) so perhaps you can serve it then. Otherwise, I would bake it into the view by generating the view on the backend with the file content as a parameter.
For more info, see;
http://expressjs.com/en/api.html#res.render
old Rails and php programmer that is new to js, tyring something and feel I am missing something pretty basic. I have a node server running a small webapp, express, ejs, jquery as well as alpinejs. (very exp with jquery, but learning alpinejs). I have a mqtt server running and can manipulate a couple of topics via my phone, and I can even see them in the node console (code below)
what I fail to understand is how to get, or maybe "bind" the subscription to a variable that I can "pass" into the express app so I can just show the mqtt message in the html. Im currently just trying to set things like fridgeFan = true or somehthing. My idea, I think, is to have mqtt update the alpinejs variable, hence updating the page, then viceversa...
Can someone point me in the general good direction of what im attemtping?
options={
clientId:"node-admin",
clean:true,
};
const express = require('express');
const app = express();
const mqtt = require('mqtt')
const client = mqtt.connect('mqtt://192.168.10.66', options)
client.on("connect",function(){
console.log("connected");
});
client.on('message',function(topic, message, packet){
console.log("message is "+ message);
console.log("topic is "+ topic);
// assume id like to bind topic and message to
// some variable that I can pass or have access to
// in the res.render calls below??
// couple of things I was trying
//document.getElementById('mqtt_div').innerHTML += topic;
//document.querySelector('[x-data]').__x.getUnobservedData().fridgeFan = message;
});
client.subscribe("sensors/sensor1",{qos:1});
app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public'));
app.get('/', (req, res) => {
res.render('index', {
title: 'Homepage'
});
});
with the above code, I can publish to "sensors/sensor1" via a phone app, I can see it in the node console, of course not the browser console.
How can I bind the "message" to a alpinejs variable so it will update?
OR do I go a different direction and put the client.on calls elsewhere, say the ejs file? in my testings, the ejs files dont know about require mqtt
You can't move your on message handler into the EJS files as they are only "executed" at the point you call render()
You can declare a global variable in the ExpressJS app and update fields with in it from the on('message',...) callback, you then pass this variable into the call to render() but this would mean that the page would only show the value at the time the page was loaded.
If you want live updates in the page as messages are published then you have one real option. That is to use a broker that supports MQTT over Websockets (nearly all modern brokers support this). With this you can load an MQTT client (either the Paho JavaScript client or you can use the MQTT.js client) into the page and subscribe to the topics you are interested in directly from the page. This way new messages are delivered directly to the page and you can then use what ever JavaScript framework you want to update the page.
Im currently refactoring an app and converting all my base code into vue. One of my requirements is to do server side rendering.
I have been follow vue ssr example along with hacker news example to help me understand ssr.
I do have however a question for which I cant find any good answer, and before further development, I want to make sure we are doing the right thing.
I want to know if its a good practice to have some actions in a vue store calling an api for server side rendering.
All the examples I have found deal with a real external endpoint they connect and perform request. But that is not the setup we have.
We do have a "normal" express app with its own endpoints; so, for example, express router looks a bit like this:
// This is our post model, it lives on the same app, so its not a external API
app.get('/posts', (req, res) => Posts.getPosts());
// Resolve request for SSR rendering, pretty much the same as in [vue ssr example](https://ssr.vuejs.org/guide/routing.html#routing-with-vue-router)
app.get(
const context = { url: req.url }
createApp(context).then(app => {
renderer.renderToString(app, (err, html) => {
if (err) {
if (err.code === 404) {
res.status(404).end('Page not found')
} else {
res.status(500).end('Internal Server Error')
}
} else {
res.end(html)
}
})
})
);
This part works fine on both client and server. If you request something to /posts you get your response back.
To have a more modular code, we are using vuex stores; being one of the actions called fetchPosts and this action is the responsible of fetching the current posts in the view.
...
actions: {
fetchPosts({ commit }) {
return $axios.get('/posts').then((response) => {
commit('setPosts', {
posts: response.data
});
});
}
},
...
I believe for client side this is good, but when rendering on the server, this is probably not optimal.
Reason being axios performing an actual http request, which will also have to implement auth mechanism, and in general, really poor performant.
My question is: is this the recommended and standard way of doing this ?
What are other possibilities that works in server and client ?
Do people actually creates separated apps for api and rendering app ?
Thanks !
I know this is an old question, but for future visitors:
The recommended way is to leverage webpack module aliases to load a server side api for the server and a client side api for the browser. You have to share the same call signature which allows the api to be "swapped".
This of course greatly improves performance as the server side api can do direct db queries instead fetching data over http.
In essence your webpack.server.config.js should have:
resolve: {
alias: {
'create-api': './create-api-server.js'
}
}
In your webpack.client.config.js:
resolve: {
alias: {
'create-api': './create-api-client.js'
}
}
Importing create-api will now load the required api.
Have a look at https://github.com/vuejs/vue-hackernews-2.0 to see a full example.
Question
How do I use Express within Firebase Cloud Functions?
Expectations
Using either of the URLs I've setup, I expect to see, "Hello from Express on Firebase!" in the console logs.
Why? My understanding is, "*" means all routes requested should response.send("Hello from Express on Firebase!");
app.get("*", (_request, response) => {
response.send("Hello from Express on Firebase!");
});
Issue
When I use, https://us-central1-myapp.cloudfunctions.net/helloWorld I get the expected Hello from Firebase! in the logs. Should I also see "Hello from Express on Firebase!"?
When I use, https://us-central1-myapp.cloudfunctions.net/api, I get a 404 error
The URL, https://us-central1-myapp.cloudfunctions.net/api is the issue. See why in the answer below.
Code
// Express
import express = require("express");
const app = express();
const cors = require("cors")({
origin: "*"
});
app.use("*", cors);
// Firebase Functions SDK
import functions = require("firebase-functions");
app.get("*", (_request, response) => {
response.send("Hello from Express on Firebase!");
});
exports.api = functions.https.onRequest(app);
exports.helloWorld = functions.https.onRequest((_request, response) => {
response.send("Hello from Firebase!");
});
tl;dr
An example of what I'm hoping to accomplish is here, but none of the code examples worked for me. I get I get a 404 error with each one.
The Express Documentation here shows a similar HelloWorld example, but I confuse how Firebase takes the place of app.listen(3000, () => console.log('Example app listening on port 3000!'))
Is cors working properly in my example code? Although I get the expected response and log, Chrome console warns: Cross-Origin Read Blocking (CORB) blocked cross-origin response https://appengine.google.com/_ah/lo....
I have a Slack App that is hitting these URLs (I hit them with chrome too). Eventually, I'd like to use Botkit middleware in my Google Cloud Functions. I don't yet grasp proper setup of Express app.use() and app.get()
Answer
I made a simple mistake by treating /api as a function when it's actually a part of the path.
By using this URL with the trailing /
https://us-central1-myapp.cloudfunctions.net/api/
I'm now hitting the Express route and function.
I am using Express to serve static assets. Frontend is AngularJS 1.x and I have html5mode enabled. Trying to implement Recaptcha is where I noticed the following in Chrome dev tools:
Uncaught SyntaxError: Unexpected token <
api.js?onload=vcRecaptchaApiLoaded&render=explicit“:1
When I click on the function to initiate the Recaptcha process I receive:
Error: reCaptcha has not been loaded yet.
So far this makes sense to be bacause I noticed the string that the first error is reporting is part of the url path to load Recaptcha from Google.
When I click on the url (api.js?onload=vcRecaptchaApiLoaded&render=explicit“:1) in chrome tools it loads my index.html! Strange!
This has be believing it has something to do with my static asset serving. I have played around with my express server until the cows came home and cannot figure out how to remedy.
Live example:
http://ninjacape.herokuapp.com
Here is my code and thank you for taking a look!
index.html
<script src=“https://www.google.com/recaptcha/api.js?onload=vcRecaptchaApiLoaded&render=explicit“ async defer></script>
express.js
var express = require('express');
var compression = require('compression');
var app = module.exports.prod = exports.prod = express();
var devAPI = 'http://localhost:1337';
app.use(compression());
app.use(express.static('.tmp'));
app.get('/*', function(req, res) {
res.sendFile(__dirname + '/.tmp/index.html');
});
var proxy = require('express-http-proxy');
app.use('/api', proxy(devAPI));
var port = process.env.PORT || 8000;
app.listen(port);
Well... I wish I had a better answer however I am just happy I got it to work. Something in the way I am statically serving files is appending any url in index.html to http://localhost:8000. To work around this I took a look at the actual request coming into Express and found the url. Then added logic to redirect that request to the real url. See commented code below for more info:
// Any requests matching /*
app.get('/*', function(req, res, next) {
// Log the original url express is tying to go to
console.log(req.url);
// This is the url found from the step above (Where are the extra characters coming from?!)
var url ='/%E2%80%9Chttps://www.google.com/recaptcha/api.js?onload=vcRecaptchaApiLoaded&render=explicit%E2%80%9C'
// Self explanatory
if (req.url === url) {
// Respond by redirecting the request
res.redirect('https://www.google.com/recaptcha/api.js?onload=vcRecaptchaApiLoaded&render=explicit')
//End this block and continue
next();
} else {
// If it doesn't match the above url, proceed as normal
res.sendFile(__dirname + '/.tmp/index.html');
}
});