I'm pretty new to using express and the responses here on StackOverflow have been very confusing. What I have is JSON data that I am retrieving using app.get(). What I want is to modify this data and send it to my index.html file. I know that I can simply use the fetch function to get the data in my index file from the get endpoint but I need to use both the app.post() and app.put() function.
I'm having trouble understanding your question.
Here's a sample code that uses axios and plain vanilla javascript to get some data from backend and then in frontend, you can modify the data. You can replace axios for fetch and it'll still work.
app.js
const express = require("express");
const bodyParser = require("body-parser");
const port = 8000;
const app = express();
/* Simulating data, a better approach would be to use some storage like MySQL... */
let data = {
name: "Elon Musk",
age: "48",
height: "1.88m"
};
app.use(express.static("public"));
/* body-parser is required so the server can parse the data sent. */
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
/* get the data... */
app.get("/api/mydata", function(req, res) {
return res.json(data);
});
/* this is where the client will post the data */
app.post("/api/newdata", function(req, res) {
data.name = req.body.name;
data.age = req.body.age;
return res.json("OK!");
});
app.listen(port, function() {
console.log("Listening on 8000");
});
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<input type="text" id="name" placeholder="Name..." value="">
<input type="text" id="age" placeholder="Age..." value="">
<button type="button" id="setValues">Change values!</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.js"></script>
<script>
window.addEventListener("load", function() {
axios.get("/api/mydata").then(function(res) {
document.getElementById("name").value = res.data.name;
document.getElementById("age").value = res.data.age;
})
});
document.getElementById("setValues").addEventListener("click", function() {
axios.post("/api/newdata", {
name: document.getElementById("name").value,
age: document.getElementById("age").value
}).then(function(res) {
console.log("Sent!");
})
})
</script>
</body>
</html>
If you have any questions, let me know!
Related
I'm using the weatherstack API and want to send the current temperature of a given city to a simple form in html using the POST method in express (or axios, if possible).
I tried to use the GET method in axios to consume the API and the POST method in express to send the result once the user enters the city they want in the search bar. The code is the following:
app.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const axios = require('axios');
const access_key = '...'
app.use(bodyParser.urlencoded({extended: false}));
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
// Successful GET in the console
// axios.get(`http://api.weatherstack.com/current?access_key=${access_key}&query=Dallas`)
// .then(response => {
// const apiResponse = response.data;
// console.log(`Current temperature in ${apiResponse.location.name} is ${apiResponse.current.temperature}℃`);
// }).catch(error => {
// console.log(error);
// });
// ----The problem-------
app.post('/', async function (req, res) {
const{response} = await axios(`http://api.weatherstack.com/current?access_key=${access_key}&query=${req.body.cityName}`)
res.send(`<p>Current temperature in ${req.body.cityName} is ${response.current.temperature} ℃</p>
<a href = '/'>Back</a>`)
});
//------------------------
app.listen({port: 4000}, () => {
console.log("Server running on localhost:4000");
});
The website
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Weatherstack</title>
</head>
<body>
<form action="/" method="post">
<p>Inform the city</p>
<input name="cityName">
<button type="submit">Send</button>
</form>
</body>
</html>
But when I run the server I get this error:
How can I solve that?
Axios return the AxiosResponse object.
export interface AxiosResponse<T = any, D = any> {
data: T;
status: number;
statusText: string;
headers: RawAxiosResponseHeaders | AxiosResponseHeaders;
config: AxiosRequestConfig<D>;
request?: any;
}
the content of your response is within the data object.
const { data } = await axios(
`http://api.weatherstack.com/current?access_key=${access_key}&query=${req.body.cityName}`
);
res.send(
`<p>Current temperature in ${req.body.cityName} is ${data.current.temperature} ℃</p><a href = '/'>Back</a>`
)
Or
const response = await axios(
`http://api.weatherstack.com/current?access_key=${access_key}&query=${req.body.cityName}`
);
res.send(
`<p>Current temperature in ${req.body.cityName} is ${response.data.current.temperature} ℃</p><a href = '/'>Back</a>`
)
I tested this code, and it works fine.
I'm currently working on a research project for my CSCI class that requires studying cyber security in great detail. Replicating what a phishing site might look like is one of the goals I've set for myself. But I'm having trouble understanding how to add information to the URL and add it to the MongoDB collection. The URL that will put the email address and password into the collection is "https://URL.com/insert?email=EMAIL#gmail.com&password=123456." I am a complete novice when it comes to creating APIs, thus I need some assistance.
I have so far made a simple form and a js file to insert the form's data into MongoDB, but I'm unable to tweak it such that it accepts parameters for URLs instead.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<h1>To MongoDB</h1>
<form class="container" method="post" action="/">
<div class="form-group">
<input class="form-control" name="email">
</div>
<div>
<textarea class="form-control" name="password"></textarea>
</div>
<button>ADD</button>
</form>
</body>
</html>
JS:
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: true}));
mongoose.connect("mongodb+srv://<USERNAME>:<PASS>#<CLUSTER>.mongodb.net/Data", { useNewUrlParser: true}, { useUnifiedTopology: true})
const dataSchema = {
email: String,
password: String
}
const Data = mongoose.model("Data", dataSchema);
app.get("/", function(req, res) {
//res.send("express is working");
res.sendFile(__dirname + "/index.html");
})
//app.post
app.post("/", function(req, res){
let newData = new Data({
email: req.body.email,
password: req.body.password
});
newData.save();
res.redirect("/");
})
app.listen(3000, function() {
console.log("server is running on port : 3000");
})
You can access the url query parameters using req.query.
If your URL is https://URL.com/insert?email=EMAIL#gmail.com&password=123456
you can access the parameters with req.query.email and req.query.password
To handle blank inputs, you have to add a check
A relevant code snippet would be:
app.get("/insert", function(req, res){
if (!req.query.email || !req.query.password) {
return res.status(400).send("failed");
}
let newData = new Data({
email: req.query.email,
password: req.query.password
});
newData.save();
res.send("success");
});
I would like to know how to pass the "myBlogs" variable that I have in my Node.js file ("server.js") to a frontend JavaScript file ("blogs.js"). Once I have access to it in the JS file, I would then map through the array that is stored in that variable and output a template for each blog in an HTML file ("blogs.html").
Later, the idea is to get the blogs data from a database (MongoDB) instead of having them hard coded. I have seen how to do this with Express and a templating engine (EJS), but as practice for a beginner, I would like to understand the basics of if and how it can be done without these tools.
My file structure:
blogs.css
blogs.html
blogs.js
server.js
server.js:
const http = require("http");
const fs = require("fs");
const myBlogs = [
{
title: "My first blog",
author: "John",
},
{
title: "My second blog",
author: "Mike",
},
];
const server = http.createServer((req, res) => {
console.log("request made");
// set header content type
let path = "";
switch (req.url) {
case "/blogs.css":
path += "blogs.css";
res.setHeader("Content-Type", "text/css");
break;
case "/blogs.js":
path += "blogs.js";
res.setHeader("Content-Type", "text/javascript");
break;
default:
path += "blogs.html";
res.setHeader("Content-Type", "text/html");
}
// send file
fs.readFile(path, (err, data) => {
if (err) {
console.log(err);
res.end();
} else {
res.write(data);
res.end();
}
});
});
server.listen(3000, "localhost", () => {
console.log("listening for requests on port 3000");
});
blogs.js:
const container = document.querySelector("div")
const html = myBlogs.map(blog => (
`<h2>${blog.title}</h2>
<p>${blog.author}</p>`
))
container.innerHTML = html;
blogs.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="blogs.css" />
</head>
<body>
<div></div>
<script src="blogs.js"></script>
</body>
</html>
blogs.css:
p {
color: red;
}
P.S.: If such an approach is completely wrong, could you please explain the correct way this would be done without the use of Express and a templating engine?
server.js
// send file
fs.readFile(path, "utf8", (err, data) => {
if (err) {
console.log(err);
res.end();
} else {
res.write(data.replace(/%MY_BLOGS%/g, JSON.stringify(myBlogs)));
res.end();
}
});
blogs.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="blogs.css" />
<script>
var myBlogs = %MY_BLOGS%;
console.log(myBlogs);
</script>
</head>
<body>
<div></div>
<script src="blogs.js"></script>
</body>
</html>
This is incredibly hacky and not a good practice at all. It basically just finds %MY_BLOGS% and interpolates a JSON encoded object. Since JSON is valid JS, it will be directly accessible in your client side JS. You can now access myBlogs in blogs.js since it's a global variable.
Instead of using HTTP you could use something like express.js with ejs to pass backend data to front end.
npm i express ejs
Now you have express.js and ejs installed write some simple code like this:
server.js
const express = require('express')
// Create new server
const app = express()
// This will read read all the files in static and add them eg;
// static/style.css would now be able to do localhost:3000/style.css
app.use(express.static("static"))
// Set the view engine from text to ejs
app.set('view engine', 'ejs')
// app.get means you are using the get method on the url "/"
app.get('/', (req,res) => {
// res.render is the method for ejs
// res.render(file, options)
res.render('blogs', {
// Now on the front end you would be able to get data
data: example
})
})
// Start listening on X port
app.listen(3000, () => {
console.log("Listening on port 3000")
})
views/blogs.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="blogs.css" />
</head>
<body>
<div>My blogs <%= locals.data %></div>
</body>
</html>
In ejs you use <% %> to run something and <%= %> to output something
Your project structure would look something like this:
static
blogs.css
blogs.js
views
blogs.ejs
server.js
You should read up on express.js and ejs
I'm trying to make a simple to do list and I can't figure out the "delete" button. I don't get any errors, the buttons just doesn't do anything. I tried a lot of things but just can't seem to get it working. I'm not sure if the problem is with form action in the ejs file or with the app.delete in my index.js or both. Thank you in advance!
ejs file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>To Do List</title>
</head>
<body>
<h1>To Do List</h1>
<form action="/todo" method="post">
<input type="text" name="task">
<button>Add</button>
</form>
<ul>
<% for(let c of todos) { %>
<li>
<%= c.task %>
<form action="/todo/<%=c.id%>?_method=DELETE" method="POST"><button>Delete</button></form>
<%= c.id%>
</li>
<% } %>
</ul>
</body>
</html>
index.js file:
const express = require('express');
const app = express();
const path = require('path');
const methodOverride = require('method-override');
const { v4: uuid } = require('uuid');
uuid();
app.use(methodOverride('_method'));
app.use(express.urlencoded({ extended: true }));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
let todos = [
{
id: uuid(),
task: '1st task, testing'
}
]
//TO DO INDEX
app.get('/todo', (req, res) => {
res.render('todo', { todos });
})
//CREATE NEW TASK
app.post('/todo', (req, res) => {
const { task, id } = req.body;
todos.push({ task, id: uuid() });
res.redirect('todo')
})
//DELETE TASK
app.delete('/todo/:id', (req, res) => {
const { id } = req.body;
todos = todos.filter(c => c.id !== id);
console.log(todos);
res.redirect('/todo')
})
app.listen(3000, () => {
console.log('LISTENING ON PORT 3000')
})
You have configured the delete route in your express app with method type DELETE that is app.delete(…), but in your html form
<form action="/todo/<%=c.id%>?_method=DELETE" method="POST">
The method is mentioned as POST. So express is not accepting it.
Form in html allows only GET and POST request.
You’ll need to trigger those delete api calls using fetch api or jquery or ajax.
Also i am not sure why that _method=DELETE is written in form action. According to me it not need there if your frontend is jinja/Django. If it’s something else then I’m not sure.
To get more insights about why it isn’t working, open the network tab in the browsers console and click your button. It should send a network call to you backend and you should be able to see there why backend isn’t doing anything for that call.
SOLVED IT
I just had to change const { id } = req.body; to const { id } = req.params;
I'm trying to make a very simple return coming from Node.js to Ajax. I'm using Express.js to make this possible.
I have code from the previous route that I did in order to write and manage JSON files and it works just fine.
The problem comes from the second route that always throws an error when I'm trying to make it return something with the JQuery ajax success method. It is the most simple form of send that I found but still doesn't work.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test 2</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
</head>
<body>
Cod: <input type="text" name="cod" id="cod">
Text: <input type="text" name="text" id="text">
<button id="boton">PRUEBA</button>
<button id="getText">GET TEXT</button>
<script>
$('#boton').click(function() {
let cod=$('#cod').val();
let text=$('#text').val();
console.log(cod);
console.log(text);
$.ajax({
type: 'POST',
data: {
cod: cod,
text: text,
},
url: 'http://localhost:1337/prueba'
});
});
$('#getText').click(function() {
$.ajax({
type: 'POST',
data: {
},
success: (result) => {
console.log(result);
},
error: (result) => {
console.log('ERROR');
},
url: 'http://localhost:1337/getText'
});
});
</script>
</body>
</html>
app.js
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/prueba', function(req, res) {
// ... First Route. The code here works just fine so I don't add it here.
});
app.post('/getText', function(req, res) {
let text = "Hola mundo";
console.log(text);
res.send(text);
});
app.listen(1337, () => console.log('Started server at http://localhost:1337!'));
When you click the 'GET TEXT' Button it enters inside the '/getText' route in app.js and console.logs the text on the node.js terminal so that's not the issue.
The issue seems to come from the res.send() function.
In the browser console it logs 'ERROR' as it appears in the ajax error method associated to the 'GET TEXT' Button. I can't find a way to make it return success.
Could anyone help me? I'm so stuck with this project for work.
looks like a CORS issue... do you serve index.html from the same location?
It works serving index.html from node
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/prueba', function(req, res) {
// ... First Route. The code here works just fine so I don't add it here.
});
app.post('/getText', function(req, res) {
let text = "Hola mundo";
console.log(text);
res.send(text);
});
app.get('*', function (req, res) {
res.sendFile('index.html', {root: '.'})
})
app.listen(1337, () => console.log('Started server at http://localhost:1337!'));
There are several options for node/express, e.g. express middleware