I'm running a server with nodejs+mongodb:
let MongoClient = require('mongodb').MongoClient.connect("mongodb://localhost:27017/mydb", { useNewUrlParser: true } ),
(async () =>{
let client;
try {
client = await MongoClient;
...
I'm creating some data-visualizations and I need a simple way to access my backend data from javascript, is this possible? Ideally I would like full access.
You have to build a bridge, e.g. using a REST API:
// server.js
// npm install express, body-parser, mongodb
const app = require("express")();
const bodyParser = require("body-parser");
const db = require("mongodb").MongoClient.connect(/*...*/);
app.use(bodyParser.json());
app.post("/findOne", async (req, res) => {
try {
const connection = await db;
const result = await connection.findOne(req.body);
if(!result) throw new Error("Not found!");
res.status(200).json(result);
} catch(error) {
res.status(500).json(error);
}
});
// ... all those other methods ...
app.listen(80);
That way you can easily connect to it on the client:
// client.js
function findOne(query) {
const result = await fetch("/findOne/", {
method: "POST",
body: JSON.stringify(query),
headers:{
'Content-Type': 'application/json'
}
});
if(!result.ok) throw await result.json();
return await result.json();
}
Note: I hope you are aware that you also allow some strangers to play with your database if you do not validate the requests properly / add authentication.
For security purposes you should never do this, but hypothetically you could make an AJAX endpoint or WebSockets server on the node application that passes the input straight to mongoDB and takes the output straight back to the client.
It would be a much better practice to write a simple API using AJAX requests or WS to prevent the user from compromising your database.
Related
My frontend code:
const user = useSelector(selectUser)
function getWatchLater(name){
axios.get('http://localhost:5000/watchlater', {user:name})
.then((response)=>{
// console.log(response.data)
setWatchLater(response.data)
})
}
The user variable holds the username and the function sends that username to the backend to get the data. Don't worry, the user variable does hold the username, i have checked it thoroughly.
My backend code:
const mysql = require('mysql2')
const express = require('express')
const cors = require('cors');
const app = express()
app.use(cors());
app.use(express.json())
app.get("/watchlater", (request, response)=>{
const user = request.body.user;
//console.log(user);
});
So basically, it will get the username and run the query. The problem is it does not get the username at all from the frontend. I tried console logging the variable user but to no avail. It returns empty.
The second argument in the axios.get() function is expecting a config object. Checkout the axios documentations on instance method and request config.
In short, in the frontend part, pass your payload into the data field of the config object, as shown in the example below.
const config = {
headers: { Authorization: token },
data: { user:name }
}
const response = await axios.get(`${url}`, config)
You need to send parameter using params object of config in case of get request. Your frontend request should change to this,
const user = useSelector(selectUser)
function getWatchLater(name){
axios.get('http://localhost:5000/watchlater', { params: { user: name }
}).then((response)=>{
// console.log(response.data)
setWatchLater(response.data)
})
}
In your express endpoint you should receive it as,
app.get("/watchlater", (request, response)=>{
const user = request.params.user;
//console.log(user);
});
I'm trying to deploy my app to Heroku in which I believe is working. Whilst testing my app via localhost it works fine, everything is posting. However after deployment and replacing all my URLs to Heroku, number of things are not working:
The GIPHY API no longer works
Nothing would post (comments and likes work but not the posting)
I have tried debugging however nothing has worked. Where am I going wrong? Please see below for details
app: https://mitnickproject1-journal-app.netlify.app/
heroku: https://journal-post-pl.herokuapp.com/print
Front-end code
const formEl = document.querySelector('form');
formEl.addEventListener('submit', postFormData)
let count=0;
async function postFormData(e) {
const current= new Date().toLocaleString()
const formData= new FormData(formEl) // console.log this to check what format this is in
const formDataSerialised=Object.fromEntries(formData) //console.log this to see what this does
const jsonObject = {...formDataSerialised, "dateTime": current, "comment": [], "EmojiCount": [0,0,0], "gifLink":gifLink, 'id': count}
console.log(JSON.stringify(jsonObject, null, 2))
try{
const options = { method: 'POST',
body: JSON.stringify(jsonObject),
headers: {
'Content-Type': 'application/json'
}
}
await fetch("https://journal-post-pl.herokuapp.com/test", options);
// const response = await fetch("https://journal-post-pl.herokuapp.com/test", {
// })
// const json = await response.json();
}catch(err){
console.error(err);
alert('There was an error')
}
}
Back End Code
app.post('/test', (req, res) => {
formData.push(req.body)
console.log(formData)
writeToJson();
res.json({success: true})
})
Any help would be appreciated
I checked out your code and tested it out while looking at the console.
Your GIPHY urls are using http instead of https. http is fine for development, but live site needs to use https. Just switch all your http urls to https and that will work.
Your server isn't set up to accept any requests from an outside source (AKA CORS). To fix this, just add app.use(cors()) to your server file.
Don't forget to put const cors = require('cors') at the top.
I want my http respond script to respond with data from my SQL server. So I can use AJAX to update HTML with data from my SQL server. And I cant find a way to do this. I'm just learning about async and I have a feeling that if I can save the output of my async function to a global var then it will work. Any help would save my headache.
My simple Listen script is:
var test = "hello!"
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write(test);
res.end();
}).listen(8080);
and my sql code is:
const util = require('util');
var mysql = require('mysql');
var con = mysql.createConnection({
host: "XXXXX",
user: "XXXXX",
password: "XXXXX",
database: "XXX"
});
var DBresult=null;
function getdb(){
const query = util.promisify(con.query).bind(con);
(async () => {
try {
const rows = await query('SELECT * FROM mylist');
DBresult=rows;
} finally {
con.end();
}
})()
}
Do NOT use any globals or shared, higher scoped variables for your asynchronous result in a server. Never do that. That is an anti-pattern for good reason because that can create intermittent concurrency problems because more than one request can be in process at the same time on your server so these would cause conflicting access to those variables, creating intermittent, very-hard-to-debug problems. I repeat again, NEVER.
You didn't describe an exact situation you are trying to write code for, but here's an example.
Instead, you use the result inside the context that it arrives from your asynchronous call. If you can use await, that generally makes the coding cleaner.
Here's a simple example:
const con = mysql.createConnection({
host: "XXXXX",
user: "XXXXX",
password: "XXXXX",
database: "XXX"
});
const query = util.promisify(con.query).bind(con);
http.createServer(async function(req, res) {
if (req.path === "/query" && req.method === "GET") {
try {
const rows = await query('SELECT * FROM mylist');
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(rows));
} catch(e) {
console.log(e);
res.statusCode = 500;
res.end();
}
} else {
// some other respone
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write("hello");
res.end();
}
}).listen(8080);
Things to note here:
Checking both path and method before handling the request.
Making callback function async so it can use await.
Making sure any promise rejection from await is caught by try/catch and an error response is sent if there's an error.
Sending result as JSON and setting appropriate content-type.
You may be using the plain http module as a learning experience, but you will very quickly find that using the simple Express framework will save you lots of programming time and make things lots easier.
If you want to use async functions, it would be something like this, take care of "async" in function for the createServer
var http = require('http');
var server = http.createServer(async (req, res) => {
async function mgetdata() {
// Async code goes here
return 'Hello, world!';
}
// Wait for the async function to complete and get its return value
const response = await mgetdata();
// Send the response
res.end(response);
});
I am building out an API using Node for the first time but a little stuck on something.
I have the following files:
My routes, routes/index.js:
const express = require('express');
const router = express.Router();
const transactionsController = require('../controllers/transactionsController');
const ordersController = require('../controllers/ordersController');
const ordersCountController = require('../controllers/ordersCountController');
router.get('/transactions', transactionsController);
router.get('/orders', ordersController);
router.get('/orders_count', ordersCountController);
module.exports = router;
My controllers, controllers/ordersCountController.js:
const ordersCountService = require('../services/ordersCountService');
const ordersCountController = async () => {
try {
const data = await ordersCountService();
console.log(data);
return data;
} catch(err) {
console.log(err);
}
};
module.exports = ordersCountController;
My service to fetch from an external API, services/ordersCountService.js:
const fetch = require('node-fetch');
const ordersCountService = async () => {
const URL = ....;
const settings = { method: 'Get'};
const res = await fetch(URL, settings);
if (!res.ok) throw new Error('Unable to retrieve data');
return await res.json();
}
module.exports = ordersCountService;
How can I pass the JSON through to the browser?
I have been trying a few things - you'll notice the return data; - but I can't figure out how to return the JSON so that it's displayed in the browser when someone visits ourdomain.com/api/orders_count.
Any suggestions as to what I am doing wrong here? I am still new to JS so sorry if I am missing something completely obvious here.
Thank you all for your time. If there is anything I can add for clarity, please don't hesitate to ask.
In your controller, ordersCountService should have 2 parameters: req and res:
The req object represents the HTTP request and has properties for the request query string, parameters, body, and HTTP headers.
The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
In this case, your controller should be:
const ordersCountController = async (req, res) => {
try {
const data = await ordersCountService();
console.log(data);
res.json({data})
} catch(err) {
console.log(err);
}
};
Save it, and open the express server, and type the route url in the browser, you would see the json format.
You could find more information about Express in this article.
Express Explained with Examples - Installation, Routing, Middleware, and More
I'm not a pro in any way but I've started and ApolloServer/Express backend to host a site where I will have public parts and private parts for members. I am generating at JWT token in the login mutation and get's it delivered to the client.
With context I want to check if the token is set or not and based on this handle what GraphQL queries are allowed. My Express/Apollo server looks like this at the moment.
const server = new ApolloServer({
typeDefs,
resolvers,
context: async ({ req }) => {
// get the user token from the headers
const token = (await req.headers.authorization) || '';
if (token) {
member = await getMember(token);
}
}
});
The problem is that this locks down the GraphQL API from any queries and I want/need to reach signup/login mutations for example.
Could anyone spread some light on this to help me understand what I need to do to get this to work.
the way i am doing it is that i will construct auth middleware even before graphql server as sometimes is needed to have information about authenticated user also in other middlewares not just GraphQL schema. Will add some codes, that you need to get it done
const auth = (req, res, next) => {
if (typeof req.headers.authorization !== 'string') {
return next();
}
const header = req.headers.authorization;
const token = header.replace('Bearer ', '');
try {
const jwtData = jwt.verify(token, JWT_SECRET);
if (jwtData && jwtData.user) {
req.user = jwtData.user;
} else {
console.log('Token was not authorized');
}
} catch (err) {
console.log('Invalid token');
}
return next();
};
This way i am injecting the user into each request if the right token is set. Then in apollo server 2 you can do it as follows.
const initGraphQLserver = () => {
const graphQLConfig = {
context: ({ req, res }) => ({
user: req.user,
}),
rootValue: {},
schema,
};
const apolloServer = new ApolloServer(graphQLConfig);
return apolloServer;
};
This function will initiate ApolloServer and you will apply this middleware in the right place. We need to have auth middleware before applyin apollo server 2
app.use(auth);
initGraphQLserver().applyMiddleware({ app });
assuming the app is
const app = express();
Now you will have user from user jwtData injected into context for each resolver as "user", or in req.user in other middlewares and you can use it for example like this. This is me query for saying which user is authenticated or not
me: {
type: User,
resolve: async (source, args, ctx) => {
const id = get(ctx, 'user.id');
if (!id) return null;
const oneUser = await getOneUser({}, { id, isActive: true });
return oneUser;
},
},
I hope that everything make sense even with fractionized code. Feel free to ask any more questions. There is definitely more complex auth, but this basic example is usually enough for simple app.
Best David