We are having problem accessing the API-key from our .env file when trying to fetch in our server.js. If we add the API-key manually to the URL in server.js it works, so the problem seems to be the connection between server.js and .env-file.
We have npm installed dotenv.
In the .env file we have written the key like this: WEATHER_API_KEY = XXXXXXXXXXXX
Does anyone know what we have done wrong?
import express from "express";
import cors from "cors";
import mongoose from "mongoose";
import crypto from "crypto";
import bcrypt from "bcrypt";
import request from "request";
import dotenv from "dotenv";
// import { stringify } from "querystring";
const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo";
mongoose.connect(mongoUrl, { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.Promise = Promise;
const port = process.env.PORT || 8080;
const app = express();
dotenv.config();
app.get("/home", (req, res) => {
let city = req.query.city;
// const request = require("request");
// const options = {
// url: `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.WEATHER_API_KEY}`,
// method: "GET",
// headers: {
// Accept: "application/json",
// },
// };
const key = "*******************";
const requesturl = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${key}`;
request(requesturl, function (error, response, body) {
let data = JSON.parse(body);
console.log(response);
if (response.statusCode === 200) {
res.send(`The weather in ${city} is ${data.weather[0].description}`);
} else {
res.send(data.message);
}
});
console.log(process.env.WEATHER_API_KEY);
});
You may try this
import 'dotenv/config';
in place of import dotenv from "dotenv"; and remove the dotenv.config(); call.
Source and explanation: https://github.com/motdotla/dotenv#how-do-i-use-dotenv-with-import
And update the request URL (which you might have changed for testing purpose) to
const requesturl = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.key}`;
Also, try defining your key without any spaces, though this is less likely to be the root cause.
WEATHER_API_KEY="XXXXXXXXXXXX"
Although the question is not specifically about React, it might be helpful for those who use React. For a React App, Environment Variables have to start with the REACT_APP_ prefix otherwise it won't work.
REACT_APP_WEATHER_API_KEY="XXXXXXXXXXXX"
Related
My fetch takes too long until it fails
I tried chrome, edge and postman
other fetch requests from pixabay api are working great
I compared the code to other projects I've made and found nothing
I also added a proxy to "package.json" as suggested on some places and it didnt work
posting below parts of my code:
controller:
import axios from 'axios'
export const getAll = async () =>{
const response = await axios.get('https://pixabay.com/api/?key=25540812-faf2b76d586c1787d2dd02736')
.then(resp=>resp)
.catch(err=>console.log(err));
return response;
}
router:
import express from "express";
import * as homeController from '../controllers/home.controller.js'
const homeRouter = express.Router();
homeRouter.get('/all', homeController.getAll)
export default homeRouter
indexjs:
import express from "express"
import dotenv from "dotenv"
import homeRouter from './routers/home.router.js'
dotenv.config();
const PORT = 3000 //process.env.PORT
console.log(PORT);
const app = express();
app.use(express.json());
app.use(homeRouter)
app.listen(PORT, ()=>{console.log(`server is connected on port ${PORT}`)})
fetch:
const getAll = async()=>{
try {
const response = await fetch (`http://localhost:3000/all`)
console.log("hu");
if (!response.ok) {
throw new Error();
}
else{
console.log("ok");
}
const responseObj = await response.json();
console.log(responseObj);
}
catch (error) {
console.log(error);
}
}
useEffect(()=>{
getAll();
},[])
Posting the answer by #Jaromanda X for everyone to see:
"see this app.get('/', (req, res) => { ... where's you req and res ??? nowhere, that's where - hint: export const getAll = async (req, res) =>{"
Apparently EVERY controller made with express needs to send a response back (in the form of res.send)
Should be obvious but somehow I missed it
Thanks everyone!
I have an app made with React, Node.js and Socket.io
I deployed Node backend to heroku , frontend to Netlify
I know that CORS errors is related to server but no matter what I add, it just cant go through that error in the picture below.
I also added proxy script to React's package.json as "proxy": "https://googledocs-clone-sbayrak.herokuapp.com/"
And here is my server.js file;
const mongoose = require('mongoose');
const Document = require('./Document');
const dotenv = require('dotenv');
const path = require('path');
const express = require('express');
const http = require('http');
const socketio = require('socket.io');
dotenv.config();
const app = express();
app.use(cors());
const server = http.createServer(app);
const io = socketio(server, {
cors: {
origin: 'https://googledocs-clone-sbayrak.netlify.app/',
methods: ['GET', 'POST'],
},
});
app.get('/', (req, res) => {
res.status(200).send('hello!!');
});
const connectDB = async () => {
try {
const connect = await mongoose.connect(process.env.MONGODB_URI, {
useUnifiedTopology: true,
useNewUrlParser: true,
});
console.log('MongoDB Connected...');
} catch (error) {
console.error(`Error : ${error.message}`);
process.exit(1);
}
};
connectDB();
let defaultValue = '';
const findOrCreateDocument = async (id) => {
if (id === null) return;
const document = await Document.findById({ _id: id });
if (document) return document;
const result = await Document.create({ _id: id, data: defaultValue });
return result;
};
io.on('connection', (socket) => {
socket.on('get-document', async (documentId) => {
const document = await findOrCreateDocument(documentId);
socket.join(documentId);
socket.emit('load-document', document.data);
socket.on('send-changes', (delta) => {
socket.broadcast.to(documentId).emit('receive-changes', delta);
});
socket.on('save-document', async (data) => {
await Document.findByIdAndUpdate(documentId, { data });
});
});
console.log('connected');
});
server.listen(process.env.PORT || 5000, () =>
console.log(`Server has started.`)
);
and this is where I make request from frontend;
import Quill from 'quill';
import 'quill/dist/quill.snow.css';
import { useParams } from 'react-router-dom';
import { io } from 'socket.io-client';
const SAVE_INTERVAL_MS = 2000;
const TextEditor = () => {
const [socket, setSocket] = useState();
const [quill, setQuill] = useState();
const { id: documentId } = useParams();
useEffect(() => {
const s = io('https://googledocs-clone-sbayrak.herokuapp.com/');
setSocket(s);
return () => {
s.disconnect();
};
}, []);
/* below other functions */
/* below other functions */
/* below other functions */
}
TL;DR
https://googledocs-clone-sbayrak.netlify.app/ is not an origin. Drop that trailing slash.
More details about the problem
No trailing slash allowed in the value of the Origin header
According to the CORS protocol (specified in the Fetch standard), browsers never set the Origin request header to a value with a trailing slash. Therefore, if a page at https://googledocs-clone-sbayrak.netlify.app/whatever issues a cross-origin request, that request's Origin header will contain
https://googledocs-clone-sbayrak.netlify.app
without any trailing slash.
Byte-by-byte comparison on the server side
You're using Socket.IO, which relies on the Node.js cors package. That package won't set any Access-Control-Allow-Origin in the response if the request's origin doesn't exactly match your CORS configuration's origin value (https://googledocs-clone-sbayrak.netlify.app/).
Putting it all together
Obviously,
'https://googledocs-clone-sbayrak.netlify.app' ===
'https://googledocs-clone-sbayrak.netlify.app/'
evaluates to false, which causes the cors package not to set any Access-Control-Allow-Origin header in the response, which causes the CORS check to fail in your browser, hence the CORS error you observed.
Example from the Fetch Standard
Section 3.2.5 of the Fetch Standard even provides an enlightening example of this mistake,
Access-Control-Allow-Origin: https://rabbit.invalid/
and explains why it causes the CORS check to fail:
A serialized origin has no trailing slash.
Looks like you haven't imported the cors package. Is it imported anywhere else?
var cors = require('cors') // is missing
I'm making a simple pdf reader application (using the pdf.js library from Mozilla), that the user selects the file and then the website automatically goes to the /reader page, and then it shows the pdf, but I don't know how should I actually transfer that pdf file to my other page, I've tried doing it like this:
This is my server.js
import express from 'express';
const app = express();
import router from '../routes/reader.js';
const port = 5500;
const ip = '127.0.0.1';
app.set('view engine', 'ejs');
app.use('/css', express.static('css'));
app.use('/node_modules', express.static('node_modules'));
app.use('/js', express.static('js'));
app.use('/docs', express.static('docs'));
app.use('/reader', readerRouter);
app.get('/', (req, res) => {
res.render('index')
});
app.listen(port, IP);
This is where I get the file from the input and send it to the specified URL, this is in a script that I've added to my home page with script tags
uploadInput.onchange = (e) => {
let file = e.target.files[0];
let fd = new FormData();
fd.append(uploadInput, file);
$.ajax({
url: '/reader',
method: 'POST',
data: fd,
cache: false,
processData: false,
contentType: 'application/pdf'
}).done(() => {
window.location.href = '/reader';
});
}
And in my /reader router, I did this:
const express = require('express');
import showPdf from '../js/pdf.js';
const router = express.Router();
router.get('/', (req, res) => {
res.render('reader');
});
router.post('/', (req, res) => {
res.redirect('/reader');
showPdf(req.body);
});
export default router;
I couldn't easily import the pdf.js script, it would throw an error saying that I can't use import outside a module etc... I'm new in node.js and I don't know how these modules work, and how should I import and use them properly, but after doing whatever that I could do to solve the importing issues, now I'm getting an error saying that pdfjsLib is not defined in my pdf.js script
This is the pdf.js script:
pdfjsLib.GlobalWorkerOptions.workerSrc = '../node_modules/pdfjs-dist/build/pdf.worker.js';
const eventBus = new pdfjsViewer.EventBus();
const pdfLinkService = new pdfjsViewer.PDFLinkService({ eventBus });
// Get document
function showPdf(file) {
let fileReader = new FileReader();
fileReader.readAsArrayBuffer(file);
fileReader.onload = () => {
let typedArray = new Uint8Array(this.result);
pdfjsLib.getDocument(typedArray).promise.then(function (_pdfDoc) {
pdfDoc = _pdfDoc;
});
}
}
it's much larger than this, but it's how I'm using the pdfjsLib and pdfjsViewer, and I'm importing them before my pdf.js script in the HTML script tags.
Why it can't find the pdfjsLib and also the pdfjsViewer? where does the router sit on my website? is this because the router can't access the pdfjsLib global variable? how should I use a script which is dependent on some global variables like this? is this approach correct at all? I mean for transferring the selected file from input and posting it to my other page.
You are exporting a variable called router and then looking for readrouter in your import. Change the import to:
import router from '../routes/reader.js
For the pdfjsLib I do not see where you are importing that library. So doing the same thing you did for router just import the pdfjsLib library. If you are using this package its:
import pdfjsLib from 'pdfjs-dist'
I am trying to upload an image with multer to cloudinary and then store the resulting url in a database column. I have the following code:
The cloudinary config file:
import { config, uploader } from 'cloudinary'
import dotenv from 'dotenv';
dotenv.config();
const cloudinaryConfig = (req, res, next) => {
config({
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});
next();
}
export { cloudinaryConfig, uploader };
The multer config file:
import multer from 'multer';
import Datauri from 'datauri';
import path from 'path';
const storage = multer.memoryStorage();
const multerUploads = multer({ storage }).single('image');
const dUri = new Datauri();
/**
* #description This function converts the buffer to data url
* #param {Object} req containing the field object
* #returns {String} The data url from the string buffer
*/
const dataUri = req => dUri.format(path.extname(req.file.originalname).toString(), req.file.buffer);
export { multerUploads, dataUri };
The entry point file(app.js)
import express from 'express';
import { urlencoded, json } from 'body-parser';
import { resolve } from 'path';
import { uploader, cloudinaryConfig } from './config/cloudinaryConfig'
import { multerUploads, dataUri } from './middlewares/multerUpload';
const app = express();
const Port = process.env.PORT || 3000;
app.use(express.static(resolve(__dirname, 'src/public')));
app.use(urlencoded({ extended: false }));
app.use(json());
app.use('*', cloudinaryConfig);
**app.post('/upload', multerUploads, (req, res) => {**
if(req.file) {
const file = dataUri(req).content;
return uploader.upload(file).then((result) => {
const image = result.url;
return res.status(200).json({
messge: 'Your image has been uploaded successfully to cloudinary',
data: {
image
}
})
}).catch((err) => res.status(400).json({
messge: 'something went wrong while processing your request',
data: {
err
}
}))
}
});
app.listen(Port, () => console.log(`Server started at http://localhost:${Port}`));
I have tried to split the functions and call them in the application routes but req.file was undefined while for the other scenario, the url wasn't generated and no error was thrown. I have also looked at the express documentation to see if I can store the result of a route in a variable but I didn't see anything like so written.
carRouter.post('/car', verifyToken, postAdchecker, cloudinaryConfig, multerUploads, postCarAd);
I want the result of the upload route which is the url generated to be passed into another route(postCarAd) as a field(imageurl). How do I make that happen?
If I send POST such /image/cover or /image/sub/ from client, the router function doesn't work at all so It sends 404. It's supposed to work but I literally have no idea. I never had this case It just doesn't work for no reason.
router
import Router from 'koa-router'
const router = new Router({ prefix: '/image' })
router.post('/cover', async (ctx, next) => {
let URLpath = ctx.request.body.files.cover.path
ctx.body = { url: URLpath }
})
router.post('/sub', async (ctx, next) => {
let URLpath = ctx.request.body.files.sub.path
ctx.body = { url: URLpath }
})
export default router
log
<-- POST /image/cover
--> POST /image/cover 404 33ms -
import code (UPDATED)
router/index.js
import compose from 'koa-compose'
import accountRouter from './account'
import mypageRouter from './mypage'
import imageRouter from './image'
import postRouter from './post'
const routes = [
accountRouter,
mypageRouter,
imageRouter,
postRouter
]
export default () => compose([].concat(
...routes.map(r => [r.routes(), r.allowedMethods()])
))
app.js
import Koa from 'koa'
import serve from 'koa-static'
import logger from 'koa-logger'
import views from 'koa-views'
import session from 'koa-session'
import passport from 'koa-passport'
import bodyParser from 'koa-body'
import path from 'path'
import routes from './routes'
import config from './config'
import form from './util/formidable'
import mongoose from 'mongoose'
mongoose.Promise = global.Promise
mongoose
.connect(config.MONGODB_URI)
.then(startApp).catch(::console.error)
function startApp() {
const app = new Koa()
const port = process.env.PORT || 3000
const dist = __dirname + '/views/'
console.log(form)
const bpOption = { IncomingForm: form, multipart: true }
app.keys = ['secret', 'key'];
require('./util/passport')
app
.use(logger())
.use(serve(dist))
.use(session({}, app))
.use(bodyParser(bpOption))
.use(passport.initialize())
.use(passport.session())
.use(views(__dirname+'/views', { extension: 'pug'}))
.use(routes())
app.listen(port, () => console.log(`[!] Server is Running on ${port}`))
}
you need help function:
// #help function record route table map
'use strict';
const fs = require('fs');
const resolve = require('path').resolve;
module.exports = function record(router, filename) {
const routeTable = fs.createWriteStream(resolve(__dirname, filename));
routeTable.write(`Update Date: ${new Date().toString()}\n\n`);
for (let len = router.stack.length, i = 0; i < len; i += 1) {
const route = router.stack[i];
routeTable.write(`URL:${route.path}\t${route.methods.join('|')}\n`);
}
routeTable.end();
};
then you can involve it by
const record = require('./record');
record(routeApp, '.routerc')
you will get .routerc file(route map) with content such as:
URL: /a/c/c POST
URL: /b/a/d GET
it can help you to solve problem. maybe work. good luck!