I am building an app similar to amazon using:
expo and react-native
aws-amplify
I want to be able to print shopping cart using Expo Print API (imagine with the app, click the "print" button prints all items from your shopping cart into a pdf). The Print API takes a HTML string as input.
There are 2 ways to generate a HTML for the shopping cart: First, hardcode it in a javascript string. This approach is painful and too old school.
const html = cart => `
<!doctype html>
<html lang="en">
<head>
...
</head>
<div>
<h1>${cart.name}</h1>
...
</div>
`
Or utilize some tool to convert a (much easier to write) react component to a HTML - react-dom-server looks the right tool. However, react-dom-server can only be used in server side instead of client side, so I try to leverage lambda function that integrates well with aws-amplify.
These are what I tried:
add amplify function
$ amplify function add
Using service: Lambda, provided by: awscloudformation
? Provide a friendly name for your resource to be used as a label for this category in the project: renderReact
? Provide the AWS Lambda function name: renderReact
? Choose the function template that you want to use: Serverless express function (Integration with Amazon API Gateway)
? Do you want to access other resources created in this project from your Lambda function? No
? Do you want to edit the local lambda function now? Yes
Please edit the file in your editor: /Users/evan/source/inventoryapp-mobile/amplify/backend/function/renderReact/src/index.js
? Press enter to continue
Successfully added resource renderReact locally.
edit amplify/backend/function/renderReact/src/app.js
import React from "react";
import ReactDOMServer from 'react-dom/server';
var express = require("express");
var bodyParser = require("body-parser");
var awsServerlessExpressMiddleware = require("aws-serverless-express/middleware");
// declare a new express app
var app = express();
app.use(bodyParser.json());
app.use(awsServerlessExpressMiddleware.eventContext());
// Enable CORS for all methods
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
app.get("/render", function(req, res) {
const reactDom = ReactDOMServer.renderToString(<div>hello world</div>);
res.json({ success: htmlTemplate(reactDom), url: req.url });
});
function htmlTemplate(reactDom) {
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>React SSR</title>
</head>
<body>
<div id="app">${reactDom}</div>
</body>
</html>
`;
}
app.listen(3000, function() {
console.log("App started");
});
// Export the app object. When executing the application local this does nothing. However,
// to port it to AWS Lambda we will create a wrapper around that will load the app from
// this file
module.exports = app;
edit amplify/backend/function/renderReact/src/package.json
{
"name": "renderReact",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"aws-serverless-express": "^3.3.5",
"body-parser": "^1.17.1",
"express": "^4.15.2",
"react": "^16.10.1",
"react-dom": "^16.10.1"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
cd amplify/backend/function/renderReact/src && yarn install
edit amplify/backend/function/renderReact/src/event.json
{
"httpMethod": "GET",
"body": "{\"name\": \"Amplify\"}",
"path": "/render",
"resource": "/{proxy+}",
"queryStringParameters": {}
}
cd back to project root, run function but err
$ amplify mock function renderReact
Using service: Lambda, provided by: awscloudformation
? Provide the name of the script file that contains your handler function: index.js
? Provide the name of the handler function to invoke: handler
? Provide the relative path to the event: event.json
Testing function locally
/Users/evan/source/inventoryapp-mobile/amplify/backend/function/renderReact/src/app.js:24
const reactDom = ReactDOMServer.renderToString(<div>hello world</div>);
^
SyntaxError: Invalid or unexpected token
at Object.Module._extensions..js (internal/modules/cjs/loader.js:947:10)
Note that I am not trying to render my <ShoppingCart /> component, just try to render the simplest <div>hello world</div> react component but no luck.
Any help? Thanks.
Related
I am working with a Nuxt.js v2.15.8 project and I am attempting to use the server middleware feature that Nuxt offers for A custom API endpoint. https://nuxtjs.org/docs/configuration-glossary/configuration-servermiddleware/#custom-api-endpoint
What I am trying to accomplish:
Use Nuxt server middleware to make a GET request to a 3rd party api to retrieve data. When I try to set this up and make the request to the endpoint in Postman, I get an error
<!doctype html>
<html data-n-head-ssr lang="en" data-n-head="%7B%22lang%22:%7B%22ssr%22:%22en%22%7D%7D">
<head>
<title>This page could not be found</title> etc....
How do I use the Nuxt server middleware to make api calls to external api's?
Nuxt.config.js
serverMiddleware: [
{
path: '/api/server-middleware',
handler: '~/api/getData.js',
},
],
~/api/getData.js
const bodyParser = require('body-parser');
const app = require('express')();
app.use(bodyParser.json());
app.all('https://jsonplaceholder.typicode.com/todos/1', (req, res) => {
res.json({ data: res.data });
});
module.exports = app;
In Postman I try to make a GET request to http://localhost:3000/api/server-middleware after running npm run dev and my Nuxt project is running.
Am I misunderstanding how this is supposed to work? Is the Server Middleware for internal api calls only?
Applying the least possible amount of changes to your shared code gives us the following
getData.js
import axios from 'axios'
const app = require('express')()
app.all('/jsonplaceholder/:id', async (req, res) => {
const { data } = await axios(
`https://jsonplaceholder.typicode.com/todos/${req.params.id}`
)
res.json({ ...data })
})
module.exports = app
/pages/index.vue
<template>
<div>
<input id="name" v-model="todoId" type="text" name="name" />
<button #click="callNuxtApi">try local Nuxt API</button>
<div>
Response from the backend:
<pre>{{ response }}</pre>
</div>
</div>
</template>
<script>
export default {
name: 'JsonPlaceholderPage',
data() {
return {
todoId: 1,
response: {},
}
},
methods: {
async callNuxtApi() {
const response = await this.$axios.$get(`/api/server-middleware/jsonplaceholder/${this.todoId}`)
console.log('response', response)
this.response = response
},
},
}
</script>
As you can see, /jsonplaceholder/:id is something more reasonable considering that it will be prefixed by /api/server-middleware/ already.
Having https:// inside of a path is not really nice to the browser overall.
PS: you need to install axios and express for it to work. #nuxtjs/axios will not work here.
This answer joins my other one here: https://stackoverflow.com/a/72102209/8816585
I am getting an error status code 404 while calling a function locally in nodejs server through firebase serve command.
My schedule.js file
const scheduleOfScheduledQuiz = async (req, res) => {
try {
const data = await getScheduledData();
return res.status(200).json({
message: "Scheduled for today:- ",
data: data
})
} catch (error) {
console.log("erro", error);
return res.status(500).json({
message: "Something went wrong....!!!"
})
}
}
module.exports = {
scheduleOfScheduledQuiz
}
getScheduledData() is a function which gets some data from the firebase realtime database
My index.js file
const functions = require("firebase-functions");
const app = require("express")();
//path to scheduleOfScheduledQuiz() function file
const scheduleOfScheduledQuiz = require("./handlers/Quiz/Scheduled_Quiz/scheduler");
app.get("*/scheduled-quiz/schedule/", scheduleOfScheduledQuiz.scheduleOfScheduledQuiz);
exports.api = functions.runWith({
memory: '2GB',
timeoutSeconds: '60'
}).https.onRequest(app);
So the error what i am getting :-
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /predicta-6e51d/us-central1/api/scheduled-quiz/schedule/%0A</pre>
</body>
</html>
with status code 404
My package.json file
Global node js version - 12
firebase node js version - 10
"express": "^4.17.1",
"firebase": "^7.15.0",
"firebase-functions": "^3.7.0",
I am running this function locally on my nodejs server through firebase serve command.
NOTE:- when i am trying to run the same function on some other file it is perfectly running but not in this file.
Please Help
Thank You
Hello i'm new to node js and i am trying send / pass post data to html but i can't seem to get it to work And was hoping maybe someone could point me in the right direction on how i can.
Server code:
const express = require("express");
const bodyParser = require('body-parser');
const app = express();
app.use(express.static("public"));
app.use(bodyParser.urlencoded({ extended: true }));
app.get("/", (request, response) => {
response.sendFile(__dirname + "/views/index.html");
});
app.post('/sendInfo', (req, res) => {
try {
console.log(`firstname: ${req.body.firstname} lastname: ${req.body.lastname}.`);
var firstName = req.body.firstname,
lastName = req.body.lastname;
res.sendFile(__dirname + "/views/info.html", { fistname: firstName, lastname: lastName });
} catch (e) {
console.error("error", e);
}
});
const listener = app.listen(process.env.PORT, () => {
console.log("Your app is listening on port " + listener.address().port);
});
views/info.html code:
<html>
<head>
<title>My Site title</title>
</head>
<body>
<h1><%= fistname %></h1>
<h1><%= lastname %></h1>
</body>
</html>
Looks like you are using the EJS template engine. So, there are a number of things that are missing in your code.
You need to tell express that you are using EJS at the template engine
The view must have an extension of .ejs not .html
You should be using res.render() and pass in the template name and the JSON data which will be used in the template
Set up a Node.js project using npm init -y, then run npm install express ejs, then create the app.js file (code given below) and finally create the views/index.ejs file (code given below). The views directory should be at the same level as your node_modules directory.
// app.js
const express = require('express');
const bodyParser = require('body-parser');
const port = process.env.PORT || 3006;
const app = express();
app.use(express.static(__dirname + '/build'));
app.use(express.json())
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ extended: true }));
app.set('view engine', 'ejs');
app.get('/fn/:first_name/ln/:last_name', (req, res) => {
res.render('index', {
first_name: req.params.first_name,
last_name: req.params.last_name
});
});
app.listen(port, () => {
console.log(`App listening on port ${port}`);
});
// views/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>First name is <%= first_name %></div>
<div>Last name is <%= last_name %></div>
</body>
</html>
Your package.json file must look something like this, use the start script
{
"name": "node-template",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.5",
"express": "^4.17.1"
}
}
Run the app using npm start
Finally, open up a browser and hit http://localhost:3006/fn/John/ln/Doe
If all goes well you will see an html rendered in the browser like this...
First name is John
Last name is Doe
Output:
Good luck.
Note: For the sake of simplicity I used GET instead of POST and used path params instead of request body. But the template engine works the same way.
I am trying to deploy a nodeJS app on firebase using this tutorial "https://www.youtube.com/watch?v=LOeioOKUKI8&t=437s", I followed exactly what was told and the app worked as intended locally using "firebase serve" but when I deployed it, POST and GET request stopped working i.e. client side code is unable to reach server side.
for example, on loading "appURL/temp" I'm getting "Content Security Policy: The page’s settings blocked the loading of a resource" error.
What I'm actually trying to do : to send JSON data from Client to server, process the data and return some result as response
What currently app does: takes input, sends it to the server on click and receive it back as response to the POST request
on Client Side (public/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script defer src="/__/firebase/7.14.6/firebase-app.js"></script>
<script defer src="/__/firebase/init.js"></script>
</head>
<body>
<h1>Home</h1>
<input type="text" id="ip">
<button onclick="send()">send</button>
<div id="text"></div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
let textDiv = document.getElementById("text")
function send(){
let ip = document.getElementById("ip").value;
axios.post('/home',ip)
.then( resp => {
textDiv.innerHTML = JSON.stringify(resp.data);
})
}
</script>
</body>
on Server Side (functions/index.js
const func = require('./add'); //this is just to wrap the string with brackets
const functions = require('firebase-functions');
const express = require('express');
const multer = require('multer');
const upload = multer();
const app = express();
app.get('/temp', (req, resp) => {
resp.send("GET Works");
console.log("GET");
})
app.post('/home', upload.single("data"), (req, res) => {
console.log(func.add(JSON.stringify(req.body)))
res.send(func.add(JSON.stringify(req.body)))
});
exports.app = functions.https.onRequest(app);
firebase.json
{
"hosting": {
"public": "public",
"rewrites":[{
"source": "**",
"function": "app"
}],
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}
Directory Structure
Versions
node : 13.6.0
express : 6.13.4
mutler : 6.13.4
I'm trying to extract the server-response text from the in iframe of Dialog Web Demo
Here's my code- Currently, the output is null:
<!DOCTYPE html>
<html lang=\"en\">
<head><meta name=\"viewport\" content=\"width=device-width, initial- scale=1, user-scalable=no\"/>
<title>Dialog</title>
</head>
<body>
<div align="center">
<iframe
id="dialog"
allow="microphone;"
width="350"
height="430"
src="https://console.dialogflow.com/api-client/demo/embedded/xxxxxxxxxxxxxxxxxxxxxxxxxxx">
</iframe>
</div>
<div align="center">
<script>
var dialogFrame = document.getElementById("dialog");
var dialogDocument = dialogFrame.contentWindow.document;
var dialogResponse = dialogDocument.getElementById("server-response");
document.write(dialogResponse);
</script>
</div>
</body>
</hmtl>
I'm expecting to extract text responded by Dialogflow, but the result is null.
Data cannot be retrieved from the HTML <iframe> element, which is only a display block. Data can be retrieved through API call; in Dialogflow, you get this data with Fulfillments.
Check below flow to deploy a Node app on App Engine, serving a Dialogflow Chat at the default endpoint, and posting fulfillment data at /fulfillment endpoint.
A) Configure fulfillment
Pay attention to the following:
URL: input your HTTPS Express POST endpoint (e.g. https://[PROJECT_ID].appspot.com/fulfillment)
leave all other fields blank
Domains: Enable webhook for all domains
Once created and saved, you still need to enable fulfillment for each Intent (and their follow-up if any) that you are using
B) Application
Create a Node App in App Engine from the console
Then deploy this app, replacing the <iframe> with yours:
app.yaml
runtime: nodejs8
package.json
{
"dependencies": {
"actions-on-google": "^2.5.0",
"dialogflow-fulfillment": "^0.5.0",
"express": "^4.16.4"
},
"scripts": {
"start": "node index.js"
}
}
index.js
'use strict';
const {WebhookClient} = require('dialogflow-fulfillment');
const express = require('express');
const bodyParser = require('body-parser');
var path = require('path');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
function WebhookProcessing(req, res) {
const agent = new WebhookClient({request: req, response: res});
console.log('Dialogflow Request headers: ' + JSON.stringify(req.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(req.body));
console.log(JSON.stringify(req.body.queryResult.queryText));
console.log(JSON.stringify(req.body.queryResult.fulfillmentText));
}
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname + '/index.html'));
});
app.post('/fulfillment', function (req, res) {
WebhookProcessing(req, res);
});
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}...`);
});
index.html
<!DOCTYPE html>
<html lang=\"en\">
<head><meta name=\"viewport\" content=\"width=device-width, initial- scale=1, user-scalable=no\"/>
<title>Dialog</title>
</head>
<body>
<div align="center">
<iframe
allow="microphone;"
width="350"
height="430"
src="https://console.dialogflow.com/api-client/demo/embedded/xxxxxxxxxxxxxxxxxxxxxxxxxxx">
</iframe>
</div>
</body>
</hmtl>
When user starts a conversation in the chat, the function WebhookProcessing outputs the logs of the body and header of each request (each message sent by user), and extracts and logs the values of both fields queryText (user's message) and fulfillmentText (Bot's reply).
Note that this is just an example of integration in App Engine, you could also consider deploying a Cloud Function, and if you work with a Firebase database, then you can use the inline editor and deploy the function from Dialogflow.