Error in the url passed when I connect to a weather api - javascript

This is my first app doing it with node.js and express. This is a basic app where I connect to an external API to show temperature and take a user input "city and feeling" and show it to the UI. I can't get the URL right. I don't know why.
I ran the app and entered data in the city and feeling text area, I debugged the app.js file and found that when it tries to fetch the URL I'm passing its data it gives the error "400 bad requests". What am I doing wrong?
the server.js
// Setup empty JS object to act as endpoint for all routes
projectData = {};
// Require Express to run server and routes
const express = require('express');
// Start up an instance of app
const app = express();
/* Middleware*/
//body-parser as the middle ware to the express to handle HTTP POST
const bodyParser = require('body-parser');
//Here we are configuring express to use body-parser as middle-ware.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Cors for cross origin allowance
const cors = require('cors');
app.use(cors());
// Initialize the main project folder , this line allows talking between server and client side
app.use(express.static('website'));
// Setup Server
const port = 8000;
const server = app.listen(port , ()=>{console.log(`the server running on localhost: ${port}`);});
//GET function
app.get('/fakeData' , getFakeData); //string represents a url path >> / means home
function getFakeData (req,res) {
// body...
console.log(projectData);
res.send(projectData);
}
var project = [];
app.get('/all', sendData);
function sendData (request, response) {
response.send(project);
console.log(project);
};
//POST function
app.post('/addAnimal' ,addAnimal);
function addAnimal (req,res) {
// body...
newEntry = {
date: req.body.date,
temp: req.body.main.temp,
feeling: req.body.feeling
}
project.push(newEntry)
res.send(project)
console.log(project)
}
website/app.js
/* Global Variables */
//let baseURL = 'http://api.openweathermap.org/data/2.5/weather?q=Egypt&APPID=';
let baseURL = `http://api.openweathermap.org/data/2.5/weather?city=`;
let apiKey = '&APPID=bb95e29dbedc4d929be90b0dd99954e0';
// Create a new date instance dynamically with JS
let d = new Date();
let newDate = d.getMonth()+'.'+ d.getDate()+'.'+ d.getFullYear();
//GET request to handle user input
document.getElementById('generate').addEventListener('click', performAction);
function performAction(e){
//Take user input
//const zipcode = document.getElementById('zip').value; //no
const feeling = document.getElementById('feelings').value;
const city = document.getElementById('zip').value;
//the fake api call
//getAnimal('/fakeAnimalData')
getTemp(baseURL ,city , apiKey )
.then (function(data) {
// body...
console.log(data)
postData('/addAnimal' ,{temp:data.main.temp ,date:newDate, feeling:feeling} )
//updateUI()
})
.then(
updateUI()
)
};
const getTemp = async(baseURL ,city , apiKey)=>{
const res = await fetch(baseURL+city+apiKey)
try{
const data = await res.json();
console.log(data)
return data;
}
catch(error){
console.log("error" , error);
}
}
//make a POST request to our route , POST to store locally user-input data
const postData = async(url='' , data={})=>{
//console.log(data);
const response = await fetch(url , {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
// Body data type must match "Content-Type" header
body: JSON.stringify(data),
});
try {
const newData = await response.json();
console.log(newData);
return newData
}catch(error){
console.log("error", error);
}
}
const updateUI = async () => {
const request = await fetch('/all');
try{
const allData = await request.json()
console.log(allData);
document.getElementById('date').innerHTML = allData[0].date;
document.getElementById('temp').innerHTML = allData[0].temp;
document.getElementById('content').innerHTML = allData[0].feeling;
}catch(error){
console.log("error", error);
}
}
website/index.js
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Weather Journal</title>
<link href="https://fonts.googleapis.com/css?family=Oswald:400,600,700|Ranga:400,700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id = "app">
<div class ="holder headline">
Weather Journal App
</div>
<div class ="holder zip">
<label for="zip">Enter Zipcode here</label>
<input type="text" id="zip" placeholder="enter zip code here">
</div>
<div class ="holder feel">
<label for="feelings">How are you feeling today?</label>
<textarea class= "myInput" id="feelings" placeholder="Enter your feelings here" rows="9" cols="50"></textarea>
<button id="generate" type = "submit"> Generate </button>
</div>
<div class ="holder entry">
<div class = "title">Most Recent Entry</div>
<div id = "entryHolder">
<div id = "date"></div>
<div id = "temp"></div>
<div id = "content"></div>
</div>
</div>
</div>
<script src="app.js" type="text/javascript"></script>
</body>
</html>

There seems no issue in your url making. I have opened http://api.openweathermap.org/data/2.5/weather?city=cairo&APPID=bb95e29dbedc4d929be90b0dd99954e0 in browser and its returning HTTP 400 Bad Request as status code and due to 400 status code the browser is telling that the request failed.
Here is response. {"cod":"400","message":"Nothing to geocode"}
The original issue, it seems, is your city parameter that your are sending.
However if you change city parameter in your url to q, it seems to work.
http://api.openweathermap.org/data/2.5/weather?q=cairo&appid=bb95e29dbedc4d929be90b0dd99954e0
Here is response. {"coord":{"lon":31.25,"lat":30.06},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"base":"stations","main":{"temp":295,"feels_like":293.65,"temp_min":294.82,"temp_max":295.15,"pressure":1015,"humidity":64},"visibility":10000,"wind":{"speed":4.1,"deg":290},"clouds":{"all":75},"dt":1584185538,"sys":{"type":1,"id":2514,"country":"EG","sunrise":1584158752,"sunset":1584201751},"timezone":7200,"id":360630,"name":"Cairo","cod":200}

Related

How can I send a POST request to display a message to an html file using axios?

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.

node express return request body empty by using API fetch POST

Learning nodejs and trying to post a form from HTML (with image upload) to nodejs (express) but the request.body returning empty object.
Tried few solutions on this site but no one is working.
Here is my code for creating a dynamic form. (HTML)
function show(data) {
const d = data.temp_form;
let content = ''
// console.log(d)
d.forEach((item) => {
if (item === 'image_backup' || item === 'image_banner') {
content += `<label for='${item}'>${item}</label><input name='${item}' type='file' id='${item}' value=''><br/>`
}else{
content += `<label for='${item}'>${item}</label><input name='${item}' type='text' id='${item}' value=''><br/>`
}
})
content += ` <input type="submit" id="handle_submit">`
getFormContianer.innerHTML = content
}
Code handling form submit
async function handleForm(e) {
e.preventDefault();
let dataForm = new FormData(e.target)
let obj = {}
dataForm.forEach((value, key) => {
obj[key] = value
if( typeof value === 'object'){
console.log(value.name)
obj[key] = value.name
}
});
let data = JSON.stringify(obj);
await fetch(file_api, {
method: 'POST',
body: data
}).then((res)=>{
return res.json();
}).then((data)=>{
console.log('api err: '+data);
}).catch((err) =>{
console.log('api err: '+ err)
})
}
Then, in my nodejs
const express = require('express');
const cors = require('cors');
const config = require('./config')
var bodyParser = require('body-parser');
var multer = require('multer');
var upload = multer();
const app = express()
const templates = require('./routes/templates-routes');
const files = require('./routes/files-routes');
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(upload.array());
app.use(express.static('public'))
app.use('/api', templates.routes);
app.use('/create', files.routes);
app.listen(config.port, () => {
console.log(`Example app listening at http://localhost:${config.port}`)
})
and in the route.js
const express = require('express');
const router = express.Router();
const {replaceValue } = require('../controllers/filesController');
router.post('/file', replaceValue);
module.exports={
routes: router
}
for the fileController.js
const replaceValue = (request, response) =>{
console.log(request.body)
response.send(request.body)}
Hope that can get some comment for you, thank you so much!
let data = JSON.stringify(obj);
await fetch(file_api, {
method: 'POST',
body: data
You are passing a string to body and haven't specified a Content-Type header so fetch will generate a Content-Type: text/plain header.
Since plain text isn't JSON, the JSON parsing middleware you have set up in Express won't process it.
await fetch(file_api, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: data
Note that this will make it a preflighted request, so make sure you follow the instructions for the CORS module to support that.

How to send data to the client and save it as a cookie

I know the basics of coding but I'm trying to understand API's, at the moment I'm trying to make an API that authorizes a user so I can see their information in a game.
Essentially I need to send data to my client from my server which is running Node.js and Express. I have managed to get the user authenticated but I then need to save that information as a cookie for later use.
The webapp starts on index.html and the API redirects the user back to auth.html.
Server Side Code
require('dotenv').config();
const express = require('express');
const {
addAsync
} = require('#awaitjs/express');
const app = addAsync(express());
const path = require('path');
const url = require('url');
const fetch = require("node-fetch");
const base64 = require('base-64');
const http = require('http');
// config libraries
const client_secret = process.env.CLIENT_SECRET;
// get env variables
function getCode(req) {
var ru = url.format({
protocol: req.protocol,
host: req.get('host'),
pathname: req.originalUrl
});
return ru.split("code=")[1];
}; // parse url to get auth code
const port = process.env.PORT || 4645;
app.listen(port, () => {
console.log(`listening on port ${port}`);
}); // set http server
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'));
}); // set '/' as index.html
app.getAsync('/auth', async (req, res) => {
res.sendFile(path.join(__dirname, 'auth.html'));
const code = getCode(req);
const options = {
method: 'POST',
headers: {
'Authorization': `Basic ${base64.encode(`35544:${client_secret}`)}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `grant_type=authorization_code&code=${code}`
}
const obj = await fetch('https://www.bungie.net/platform/app/oauth/token/', options); // response
const data = await obj.json(); // json response = data
console.log(data);
// send json to client
res.json(data);
res.end();
});
app.get('/logout', async (req, res) => {
res.redirect('/');
});
Client Side Code (index.html)
<head>
<script>
// code
</script>
</head>
<body>
index.html <br>
<a href='https://www.bungie.net/en/OAuth/Authorize?client_id=35544&response_type=code'>log in</a> <br>
</body>
Client Side Code (auth.html)
<head>
<script>
// catch json from server
const options = {
url: '/auth',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
fetch(options).then(response => {
console.log(response);
})
</script>
</head>
<body>
auth.html <br>
<a href='/logout'>log out</a>
</body>
I know it's a lot but I hope someone can help me on this...
Thanks.
Edit:
I forgot to say that currently the client does not recieve the information at any point, and if it did i am unsure how to catch the response at the right time...
Thanks to everyone who already responded.
Without bothering to puzzle-out your code ... "never trust the client."
Never try to send the client any meaningful data as the content of a cookie. The cookie's value should always be a perfectly-meaningless value – a "nonce" – which you can then refer to in order to look up anything you need to know from your server-side database. "You can never trust the client-side."

Cant find the problem an express server problem

i have an express server which has the code:
// Setup empty JS object to act as endpoint for all routes
projectData = {};
// Require Express to run server and routes
const express = require('express');
// Start up an instance of app
const app = express();
/* Dependencies */
const bodyParser = require('body-parser');
/* Middleware*/
//Here we are configuring express to use body-parser as middle-ware.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Cors for cross origin allowance
const cors = require('cors');
app.use(cors());
// Initialize the main project folder
app.use(express.static('website'));
const port = 8000;
// Setup Server
const server = app.listen(port, listening);
function listening(){
// console.log(server);
console.log(`running on localhost: ${port}`);
};
app.get('/all', sendData);
function sendData (req, res) {
res.send(projectData);
};
app.post('/all', receiveData);
function receiveData (req, res) {
projectData.temp = req.body.temp;
projectData.date = req.body.date;
projectData.ures = req.body.ures;
res.send(projectData);
console.log(projectData);
}
so simply i am making a weather journal app which receives data from an API and shows it to the user and this is the index look like:
so basically the user is going to write the zip code and feelings and when clicking on the button generate the entry should contain the information like this
but when the user click the button generate this shows and the user have to click it again in order to show the information like the top picture:
and this is the JavaScript code for the client-side:
/* Global Variables */
let baseURLz = 'http://api.openweathermap.org/data/2.5/weather?zip=';
let baseURLa = '&appid=';
const apiKey = '8e017daef09d7f784c8595696bdcb587';
// Create a new date instance dynamically with JS
let d = new Date();
let newDate = d.getMonth()+'.'+ d.getDate()+'.'+ d.getFullYear();
document.getElementById('generate').addEventListener('click', performAction);
function performAction(e){
const zipcode = document.getElementById('zip').value;
const ures = document.getElementById('feelings').value;
getWeather(baseURLz, zipcode, baseURLa, apiKey)
.then(function(data){
console.log(data);
postData('/all', {temp: data.main.temp, date: newDate, ures: ures});
})
.then(
updateUI()
)
}
const getWeather = async (baseURLz, zipcode, baseURLa, apikey)=>{
const res = await fetch(baseURLz+zipcode+baseURLa+apikey+'&units = imperial')
try {
const data = await res.json();
console.log(data)
return data;
} catch(error) {
console.log("error", error);
// appropriately handle the error
}
}
const postData = async ( url = '', data = {})=>{
const res = await fetch(url, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
});
try {
const newData = await res.json();
return newData;
}catch(error) {
console.log("error", error);
}
};
const updateUI = async () => {
const req = await fetch('/all');
try{
const allData = await req.json();
document.getElementById('date').innerHTML = 'Date: '+allData.date;
document.getElementById('temp').innerHTML = 'Temperature: '+allData.temp+'°F';
document.getElementById('content').innerHTML = 'Feelings: '+allData.ures;
}catch(error){
console.log("error", error);
}
}
and this is the html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Weather Journal</title>
<link href="https://fonts.googleapis.com/css?family=Oswald:400,600,700|Ranga:400,700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id = "app">
<div class ="holder headline">
Weather Journal App
</div>
<div class ="holder zip">
<label for="zip">Enter Zipcode here</label>
<input type="text" id="zip" placeholder="enter zip code here">
</div>
<div class ="holder feel">
<label for="feelings">How are you feeling today?</label>
<textarea class= "myInput" id="feelings" placeholder="Enter your feelings here" rows="9" cols="50"></textarea>
<button id="generate" type = "submit"> Generate </button>
</div>
<div class ="holder entry">
<div class = "title">Most Recent Entry</div>
<div id = "entryHolder">
<div id = "date"></div>
<div id = "temp"></div>
<div id = "content"></div>
</div>
</div>
</div>
<script src="app.js" type="text/javascript"></script>
</body>
</html>
please i want to figure out where is the problem causing this to happen.

Passing data from Client to Server

In my code I want to pass an id from client to server.
I am trying to use fetch setting the Content-Type to Application/json but it looks like we have some problems (I analized the request and it doesn't create the body).
Is there a simply way to pass data from client to server?
{#each accounts}}
<form action="/users/chat" method="POST">
<div class="form-group">
<p>{{#index}}</p>
<label for="name" value={{username}}>{{username}}</label>
</div>
<div class="form-group">
<label for="name">{{email}}</label>
</div>
<button class="myButton" id="{{#index}}">chat</button>
</form>
{{else}}
<p>No account</p>
{{/each}}
<script>
const buttons = document.getElementsByClassName('myButton');
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function(e) {
let ident=this.id;
console.log(ident);
console.log('button was clicked');
fetch("/myurl",{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
body: JSON.stringify({id : ident})
})
}
</script>
Here is the code of the server:
var express = require('express');
var router = express.Router();
var app = express();
var bcrypt = require('bcryptjs');
const db = require('../config/database');
const Account = require('../models/Account');
const chat = require('../models/chat');
const Sequelize = require('sequelize');
const Op = Sequelize.Op;
var passport = require('passport');
LocalStrategy = require('passport-local').Strategy;
const {ensureAuthenticated}=require('../config/auth');
app.use(express.urlencoded());
app.use(express.json());
//Socket
const PORTS = process.env.PORT || 7001;
var client = require('socket.io').listen((PORTS, console.log`SOCKET started on port ${PORTS}`)).sockets;
var password;
var username;
var accounts;
//Register
router.get('/register', function(req,res){
res.render('register');
});
//CHAT
router.get('/chat', ensureAuthenticated, (req,res)=>{
console.log(request.body.user.id);
res.render('chat');
});
module.exports=router;
Having checked carefully, this line here in your request from client is the cause fetch("/myurl",{ ...
If you see the guide at MDN, the usage is fetch('http://example.com/movies.json'). Fetch API expects complete url/uri along with the protocol (http, https) etc.
So your request should be like:
fetch("http://yourdomain.com", { ...

Categories