How to pass database connection in NodeJS - node.js

I'm using the express framework in NodeJS with typescript in the backend.
I have a very easy architecture in my index file:
index.html
import express = require("express");
import mongoClient = require("mongodb");
import apiRoutes from "./routes";
import { MONGO_CONNECTION } from "./config/mongo_config";
const app = express();
mongoClient.MongoClient.connect(MONGO_CONNECTION, { }, (err: any, mclient: any) => {
if (err) throw err;
const mongodb = mclient.db('test');
app.use('/api', isOnline, apiRoutes);
app.listen(80, () => console.log('API running on port 80'));
});
The express routes are separated in an other file (in my version it is separated in multiple file, just to keep it simple), here just an example:
routes/index.ts
import express = require("express");
import { Router } from "express";
const router = Router({mergeParams: true});
router.get('/example', (req: express.Request, res: express.Response) => {
res.json('Hello World');
});
export default router;
I don't want to use mongoose. So is there any way to pass the DB connection to another file without connecting again?

You can export an object in your index.js
export const mongodb = {};
And then instead of this:
const mongodb = mclient.db('test');
Use:
mongodb.connection = mclient.db('test');
or something like this.
Then other parts of the code can import it but make sure that it is not undefined before you use it because it may have not been initialized yet.
Another option would be to export a promise that would be resolved with a connection established:
export const mongodb = new Promise((resolve, reject) => {
// establish your connection here ...
resolve(mclient.db('test'));
// ...
);
And then in your importing code you will also use it with await.

Related

404 when trying to get response from backend using axios

I am trying to get function result from backend to frontend via axios but it returns 404 every time.
I managed to send request to backend and activate function but on geting result it started returning 404
route in app.ts
import cardRoute from './routes/test';
const app = express();
app.use('/test', cardRoute);
./routes/test.ts (backend)
function test_load() returns string
import express from 'express';
import { test_load } from '../cardpull';
const router = express.Router();
router.post('./test-bed',
async (req, res) => {
let cards = test_load()
res.send(cards);
},
);
export default router;
Frontend call
async function GetCard() {
var cards = await axios.post<string>('/test/test-bed');
return cards;
};
your route is not valid
router.post('./test-bed',
async (req, res) => {
let cards = test_load()
res.send(cards);
},
);
should be:
router.post('/test-bed',
async (req, res) => {
let cards = test_load()
res.send(cards);
},
);
and on your axios URL, maybe you need to include the host and port because if you define only the endpoint, it will hit your frontend host and port,
example if you open express on localhost:3000
then the axios will be
axios.post('http://localhost:3000/test/test-bed')
note: I didn't write the answer with typescript, but with javascript style should be clear enough.

How to pass sequelize through express routes to controller in MVC model in node when using ES6 import/export?

I'm trying to refactor some existing code into an MVC model, and am not sure if I'm messing up the structure, or if I just can't figure out how to pass a variable, but, assuming my structure is good, how do I pass a sequelize instance through an Express route to a controller? Here's my code, hopefully simplified for clarity:
Structure:
src/
db.js
routes.js
server.js
controllers/mycontroller.js
models/mymodel.js
server.js:
'use strict';
import express from 'express';
import Sequelize from 'sequelize';
import { router as routes } from './routes';
import db from './db';
const app = express();
try {
await db.authenticate();
console.log('Connection has been established successfully.');
} catch (error) {
console.error('Unable to connect to the database:', error);
}
db.myTable.sync(); // this works fine
app.use(express.urlencoded({ extended: false }));
app.use(routes); // this, I think, needs to pass db.myTable
app.listen( 3300, () => {
console.log('Listening on 3300');
});
db.js:
'use strict';
import Sequelize from 'sequelize';
import myTableModel from './models/mymodel';
const sequelize = new Sequelize('sqlite::memory');
const db = {};
db.authenticate = () => sequelize.authenticate();
db.myTable = myTableModel(sequelize);
export default db;
routes.js:
import express from 'express';
export const router = express.Router();
import MyController from './controllers/mycontroller';
const myController = new MyController();
... // other routes elided for brevity
router.post('/test', myController.store); // that db.myTable I thought I needed to pass above,
// I think I need to pass again here. Or, alternatively, I could put a constructor into
// MyController and pass it as an arg above when I call 'new MyController', but I still have to
// get it down here into this routes file.
mycontroller.js:
'use strict';
import MyTableModel from '../models/mymodel'; // This was an experiment I tried, but in retrospect,
// it of course makes no sense. I don't need to import the model, I need to have passed the
// instantiated model down here somehow
export default class MyController {
store = async (req, res, next) => {
await MyTable.create({ full: req.body.fullUrl}); // This fails (of course), because
// MyTable.create doesn't exist here.
res.redirect('/');
}
}
So, back to the question: assuming this structure looks correct (feel free to comment on that as well), how do I get that MyTable sequelize object passed all the way through to the controller, so it can do its thing?
Maybe in calling directly the model ?
'use strict';
import { myTable } from '../db';
export default class MyController {
store = async (req, res, next) => {
await MyTable.create({ full: req.body.fullUrl});
res.redirect('/');
}
}

How do i fill my parameter req.body with axios (Vue.js) to my Express.js server

Im trying to send a connect call to my api from my vue (i use vue.js),
but when i get the object req.body in my back, the object is empty
I've read this : Axios post request.body is empty object
but it didn't help me
(it works from Postman with the body filled and the option x-www-form-encoded)
i got this got from my Vue :
My vue service.js
import Axios from 'axios';
class APIClient {
constructor () {
this.client = Axios.create({
baseURL: 'http://localhost:8080'
});
}
async connect () {
const params = new URLSearchParams();
params.append('mail', 'test');
params.append('pwd', 'mypwd');
return await this.client.get('/api/user/auth', params);
}
and i got this in my back :
index.ts :
import express from "express";
var cors = require('cors');
import "reflect-metadata";
var bodyParser = require('body-parser')
const http = require('http');
const MainRouter = require('./routes/main_router');
let port = 8080;
const server = express();
server.use(cors({origin: true}))
server.use(bodyParser.json());
server.use(bodyParser.urlencoded({extended: true}))
let mainRouter = new MainRouter(server);
const httpServer = http.createServer(server);
httpServer.listen(port);
console.log('Server is listening');
and the main_router.ts
import express from 'express';
import mysql from "promise-mysql";
export default class MainRouter {
public server: express.Express;
constructor (server: express.Express) {
super();
this.server = server;
this.server.get("/api/user/auth", async (req: any, res: any) => {
if (req.body) //the req.body is equal to {} instead of {mail: 'test', ...
return res.json(await this.userManager.getUserByCredidentials(req.body));
else return res.json([])
});
}
}
module.exports = MainRouter;
I don't know if i have something to add in my express server or in my vue with axios ?
You are passing the mail and pwd as GET parameters and not at the request body. You can access the using req.query, but ....
You should avoid sending creds as parameters of the url with GET, use the body and POST instead. For more information see this post.
Here is an example:
return await this.client.post('/api/user/auth', {
mail: "test",
pwd: "mypwd"
});
and of course do not forget to change this.server.get("/api/user/auth",... to this.server.post("/api/user/auth",...

Trouble getting Express/React routes to work

I'm just learning Express/React and I'm trying to get set up with routes and basic database connections. I suspect I'm missing something very simple. I've tried to boil it down to the following.
Backend
server.js:
require('dotenv').config({path: '../.env'});
const mysql = require('mysql');
const express = require('express');
const bodyParser = require('body-parser');
const port = process.env.PORT || 5000;
const app = express();
const router = express.Router();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
const users = require('./routes/api/users');
app.use('/api/users', users);
const events = require('./routes/api/events');
app.use('/api/events', events);
const db = mysql.createConnection({
host: process.env.DB_HOST,
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD
});
db.connect(function(err) {
if (err) throw err;
console.log('MySQL Connected!');
})
app.listen(port, () => console.log(`Listening on port ${port}`));
/routes/api/events.js:
const express = require('express');
const router = express.Router();
// GET api/events
router.get('/', (req, res) => {
res.send({id: "1", name: "hi"});
});
module.exports = router;
Frontend
App.js:
import React, { Component } from 'react';
import EventList from './components/EventList';
class App extends Component {
render() {
return (
<div className="App">
<EventList/>
</div>)
}
}
export default App;
/components/EventList.js:
import React, { Component } from 'react';
import axios from 'axios';
class EventList extends Component {
constructor() {
super();
this.state = {
events: []
}
}
componentDidMount() {
axios.get('/api/events')
.then(events => {
this.setState({events: events.data})
})
.catch(err => console.log(err))
}
render() {
var events = this.state.events;
return (
<div>
<p>Events:</p>
<ul>
{ events.map(({ id, name }) => (
<li>{name}</li>
))}
</ul>
</div>
)
}
}
export default EventList;
The error I get is http://localhost:3000/api/events 500 (Internal Server Error). What am I missing? I have truly scoured all of the docs I can find, but I'm not quite getting it.
Edit
I haven't changed anything, but now I'm getting a 404 (Not Found) instead. I had been getting a 500 for awhile, so it wasn't a momentary fluke. I'm not sure what could have changed.
Update
It may help to know that the .env variables I'm pointing to are actually for a remote MySQL database (i.e., DB_HOST != localhost, but a remote URL). Eventually, I'd like to connect the GET call on the events route to that db, but since it doesn't work with what I have here I figured my first issue to solve was upstream. As noted in comments, the PORT var I'm loading in is 3306. When I start the server, it says it's listening on 3306 as expected.
I think you are running your server on port 5000 and front on port 3000. if you request events with http://localhost:5000/api/events instead of /api/events, you would get 200 status code with your json data.
// as is
axios.get('/api/events')
// to be
axios.get('http://localhost:5000/api/events')
You could try typing componentDidMount function like this.
componentDidMount = async () =>{
//like this
}
In addition, I would recommend making the GET ALL its own function so you could just invoke in the componentDidMount function. whenever you run another CRUD action it will automatically update your events for you and instead of setting state every time you can invoke the this.getEvents() again to update it that way.
componentDidMount = async () =>{
this.getEvents()
}
Also you need to add this package (npm install cors) its so you can connect your api to your frontend.
Import it like this in your server.js file
const cors = require('cors')
app.use(cors())
You should add a proxy inside package.json in frontend like this.
"proxy": "http://localhost:5000",

Has no exported member

I am new in Typescript. I am using express js and I have the folowing problem. When I run the server it appear '...../routes.ts' has no exported member 'router'. I ve been searching but I didnt succeed. These are my files.
In my src/index.ts
import "reflect-metadata"
import * as express from "express"
import { router } from "./routes"
async function main() {
const app = express()
app.get('/api',router)
app.listen(3000, () => console.log("Server running"))
}
main()
In my src/routes.ts
import * as express from "express";
var router = express.Router();
router.route('/user').get((req, res) => res.send("Hello world"));
module.exports = router;
This isn't a Typescript issue, you aren't exporting router as a named export so the { ... } syntax won't work.
Given it appears to be the default export, you can use
import router from './routes.js'
Alternatively, if you are using a transpiler that supports the export syntax, you could export your router as a named export i.e.
export const router
This would allow you to import via { router }.

Resources