I´m making an API with node and express that fetches data from an SQLite database and sends as a response. My database is structured as follows:
I have a set of tables, one for each customer. These tables contain a set of rows, one for each page the customer has.
For example say that I have two customers; Fruit and Vegetables. The dream scenario would be that localhost:8080/fruit leads to a home page for Fruit, and that localhost:8080/fruit/apples leads to the apples-page for fruit, without me having to manually program all the specific routes. I know about the :id parameter in express, and the functionality I would like is basically using the :id twice, like localhost:8080/:id1/:id2.
Here´s my code:
import express from "express";
const app = express();
const PORT = 8080;
app.listen(PORT, () => console.log(`It's alive on http://localhost:${PORT}`));
app.use(express.json());
app.use(express.static("start"));
app.use(express.urlencoded({ extended: true }));
app.set("view engine", "ejs");
//* These is the router in use
import router from "../controller/router.js";
// * This defines what URI is used for the router
app.use("/", router);
import express from "express";
import { fetchContent } from "../model/model.js";
const router = express.Router();
//* Sends out the ejs (basically HTML) on start URL "localhost:8080"
router.get("/", function (req, res) {
converter();
res.render("../pages/start.ejs");
});
//* Querys the database, the table ":id"
router.get("/:id", async function (req, res, next) {
let id = req.params.id;
let sqlQuery = `SELECT page_content FROM ${id} WHERE page_name = "about";`;
const content = await fetchContent(sqlQuery);
if (content == "404") {
res.status(404).render("../pages/404.ejs");
} else {
res.status(200).send(JSON.parse(content));
next();
}
});
export default router;
import sqlite3 from "sqlite3";
const db = new sqlite3.Database(
"path/to/my/db.db"
);
export function fetchContent(sqlQuery) {
return new Promise((resolve, reject) => {
db.all(sqlQuery, [], (err, rows) => {
if (err) {
resolve("404");
} else {
rows.forEach((row) => {
resolve(row.page_content);
});
}
});
});
}
I have made this work with one :id, and the API fetches whatever table the :id is, but right now it´s a predetermined page, and I can´t go anywhere from there. If my explanation of what I would like was hard to follow just ask and I´ll try to explain better. :D
This was actually really simple. All I had to do was to make a new parameter. On my old code I had this:
router.get("/:id", async function (req, res, next) {
let customerId = req.params.id;
let sqlQuery = `SELECT page_content FROM ${id} WHERE page_name = "about";`;
});
But now I renamed the old one and made a new one, and now my code looks like this:
router.get("/:customerId", async function (req, res, next) {
let customerId = req.params.customerId;
let sqlQuery = `SELECT page_content FROM ${customerId} WHERE page_name = "about";`;
});
router.get("/:customerId/:pageId", async function (req, res, next) {
let customerId = req.params.customerId;
let pageId = req.params.pageId;
let sqlQuery = `SELECT page_content FROM ${customerId} WHERE page_name = "${pageId}";`;
});
Related
I am trying to create a simple CRUD app. I was trying to set up the first backend route but I am stuck and can't figure out what is wrong with my code or what I am missing.
If I try to test the route with Insomnia, it doesn't return any error, but it targets the basic "/" route and returns the console.log('OK') instead of creating an item in MongoDB. Here is my code:
// app.js file
require("./db");
const express = require("express");
const app = express();
require("./config")(app);
const backoffice = require('./routes/backoffice');
app.use('/api/backoffice', backoffice);
app.use('/', (req, res) => {
res.send('OK')
});
module.exports = app;
// route file backoffice.js
const router = require("express").Router();
const Item = require("../models/Item");
router.post('/backoffice', (req, res, next) => {
console.log(req.body);
const {title, description} = req.body;
Item.create({
title,
description
})
.then(response => {
console.log(response)
res.status(200).json({message: 'New item added succesfully'})
})
.catch(err => res.json(err))
})
module.exports = router;
I am new at Node.js and trying to make an API that will do CRUD operations in sql server. The problem for me is that I can get the data but cannot post it, and get the error "cant get /". I know there are similar questions about this subject but nothing works for me so I thought maybe my code has different kinds of error. Any help will be appreciated and save my life in a way. Also, this is my first question on stackoverflow, sorry for the possible mistakes..
Here is the server.js
const sql = require('mssql');
const express = require('express');
const bodyParser = require('body-parser');
var port = process.env.port || 5000;
const sqlConfig = require('./connection/connect')
const app = express();
app.use(express.json()); // json desteklemesi için
app.use(express.urlencoded({ extended: true }));
app.get("/test", (req, res, next) => {
new sql.ConnectionPool(sqlConfig).connect()
.then(pool => {
return pool.query('select * from tblProfile')
})
.then(result => {
res.send(result);
})
})
app.post('/test', (req, res) => {
let name = req.query.name;
let lastname = req.query.lastname;
let email = req.query.email;
let password = req.query.password;
let sql = "INSERT INTO tblProfile(name,lastname,email,password) VALUES(? ? ? ?)";
conn.query(sql, [name, lastname, email, password], (err, result) => {
if (err) throw err;
res.write("inserted.");
res.end();
});
app.listen(port, () => {
console.log("working: " + port)
})
});
This is the connect.js
var sqlConfig = {
server: '192.168.1.2',
database: 'profile',
user: 'username',
password: 'user',
};
module.exports = sqlConfig;
This is happening because you aren't responding or sending anything to that route
So if you want to get rid of the error
Run
app.get('/', (req,res)=>{
res.send('hello world')
}
But if you want to send a static file to the route
Create a folder call public * note it can be anything
And type
var path = require('path');
app.use(express.static(path.join(__dirname, 'public')));
Then you can access code in the dir
And as for the writing I think you should try this
app.post('/test', (req, res) => {
let name = req.body.name;
let lastname = req.body.lastname;
let email = req.body.email;
let password = req.body.password;
let sql = "INSERT INTO tblProfile(name,lastname,email,password VAUES(? ? ? ?)";
conn.query(sql, [name, lastname, email, password], (err, result) => {
if (err) throw err;
res.write("inserted.");
res.end();
});
Change query to body
Since you installed body-parser
Taking a quick look over your code, the only issues I can see are in your query to submit the data. Within your query statement, I added a closed parentheses after the variables to be entered into the database and made a typo correction to the word Values. I also changed up how the data is retrieved from req.query to destructure it and simply the code a bit. Based on everything else I saw, and the fact that you are able to get data from the database, this should work out fine. If it doesn't, I would recommend inserting some console.log() statements in the post query to see where it might be having issues and why. For example, you could run console.dir(req.query); in your post route to see what data is actually coming from the req and make sure it is all there. If something is missing, then the query won't actually execute. If this doesn't work, let me know, along with the information from any console logs you did and I'll take another look at it.
const sql = require('mssql');
const express = require('express');
const bodyParser = require('body-parser');
var port = process.env.port || 5000;
const sqlConfig = require('./connection/connect')
const app = express();
app.use(express.json()); // json desteklemesi için
app.use(express.urlencoded({ extended: true }));
app.get("/test", (req, res, next) => {
new sql.ConnectionPool(sqlConfig).connect()
.then(pool => {
return pool.query('select * from tblProfile')
})
.then(result => {
res.send(result);
})
})
app.post('/test', (req, res) => {
//console.dir(req.query);
let {name, lastname, email, password} = req.query;
let sql = "INSERT INTO tblProfile(name,lastname,email,password) VALUES(? ? ? ?)";
conn.query(sql, [name, lastname, email, password], (err, result) => {
if (err) throw err;
res.write("inserted.");
res.end();
});
app.listen(port, () => {
console.log("working: " + port)
})
});
I am making a Portfolio application with nodeJS and express. I want to implement an admin panel which I can create,delete, update and edit my skills,experience,about etc, but I don't know how can I keep those admin routes secret and what kind of authentication to make.If we can do by putting Basic authentication on post,patch,delete route then how will we implement basic authentication on routes.
index.js
const express = require('express');
const app = express();
var cors = require('cors');
require('./db/mongoose')
const menuRouter = require('./routers/menu')
const skillRouter = require('./routers/skill')
const aboutRouter = require('./routers/About')
const experienceRouter = require('./routers/Experience')
const resumerouter = require('./routers/Resume')
const userRouter = require('./routers/user')
const port = process.env.PORT || 4000;
app.use(express.json());
app.use(cors());
app.use(menuRouter);
app.use(skillRouter);
app.use(aboutRouter);
app.use(experienceRouter);
app.use(resumerouter);
app.use(userRouter)
app.listen(port, () => {
console.log("Server is runing on port" + port)
});
skill.js
const express = require('express');
const Skill = require('../model/skill');
const router = new express.Router();
router.post('/skill', async (req, res) => {
const skill = new Skill(req.body);
try {
await skill.save();
res.status(201).send(skill);
} catch (e) {
console.log(e);
res.status(400).send(e);
}
})
router.get('/skill', async (rq, res) => {
try {
const skill = await Skill.find({});
res.status(201).send(skill);
} catch (e) {
res.status(400).send(e);
}
})
module.exports = router;
As specified in the comments, I would refactor your code a bit, seems messy and you're kind'a repeating yourself every line you import a route, so, you should do it better as well...
have an index.js file in your /routers folder with the content of the demo repo I've made for other StackOverflow question
then, to separate things, I would do something like:
const routes = require('./routes')
...
const protectRouteWithApiKey = (req, res, next) => {
const auth = req.headers['x-apikey']
if (auth && auth === '<YOUR API KEY>') return next()
return next(new Error('403 | Authorization is missing or value is wrong'))
}
...
app.use('/api', protectRouteWithApiKey, routes) // point to your routes and protect access
app.use('/', defaultEngine) // your engine to render html
you would then have a protected route in /api/* and normal routes for everything else
A middleware where you detect if the logged user is the admin?
In this sample checking by the email, and you can save the adminemail as a global variable
ensureAdmin: function(req, res, next) {
if (req.isAuthenticated()) {
if (req.user.email === adminemail) {
return next();
} else {
return res.redirect('/adminsecretroute');
}
}
res.redirect('/');
}
given the following code:
const https = require('https');
const fs = require('fs');
var path = require('path');
const express = require('express');
const app = express();
const router = express.Router();
const pool = require('./mysqldb.js');
const pathView = __dirname + "/views/";
const IMGPath = "/public";
var bodyParser = require("body-parser");
const listenPort = 8010;
var id = null ;
router.get('/details/:id', async function (req, res, next) {
id = req.params.id;
if ( typeof req.params.id === "number"){id = parseInt(id);}
res.render('details.ejs' );
});
The main goal is to save that req.params.id(the id from the url) in the id variable before serving the details.ejs file.I tried to remove the async but didn't work.Can you help me please?
You can make use of the await keywords inside your async function like so:
router.get('/details/:id', async function (req, res, next) {
await (() => { id = req.params.id; })(); // Will run first
await (() => { res.send(id); })(); // Will run second
})
res.send(id) or res.render('details.ejs') ( in your case ) will run after the id is retrieved
It seems to be working fine for me. Below, I launch this server, then I go to http://localhost:3050/123 and suddenly I'm console.logging '123' over and over again, and the correct text displays on the screen.
So... idk what else if going on for you, but it might help if you try your best to distill your code down to the simplest possible iteration to try to debug. Just try to replicate it elsewhere. You might find one of your additional modules is causing an issue.
const express = require('express')
const app = express();
const port = 3050;
let id = null;
app.get('/:id', (req, res) => {
return res.send('Hello World!')
});
app.get('/details/:id', (req, res) => {
if (req.params.id){
id = req.params.id;
}
// 'id' will appear in browser
return res.send(`See details for id: ${id}`);
});
// console logs of 'id'
setInterval(() => { console.log(`id is currently ${id}`); }, 1000);
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
I don't think async/await will have any effect on this specific issue. I doubt they're related.
This seems to work for me,
router.get('/details/:id', async function (req, res, next) {
id = typeof req.params.id === 'number' ? parseInt(id) : req.params.id;
console.log(id);
res.send('details.ejs' );
});
I have followed the node-postgres.org instruction at https://node-postgres.com/guides/async-express to connect via async/await to my postgres table users.
Navigating to localhost:3000/users/1 will return the JSON string for user 1 in the browser. I have extended this a bit to return all users at localhost:3000/users. My routes/user.js script is:
const Router = require('express-promise-router')
const db = require('../db')
// create a new express-promise-router
// this has the same API as the normal express router except
// it allows you to use async functions as route handlers
const router = new Router()
// export our router to be mounted by the parent application
module.exports = router
router.get('/:id', async (req, res) => {
console.log('Where id = ');
const { id } = req.params
const { rows } = await db.query('SELECT * FROM users WHERE id = $1', [id])
res.send(rows[0])
})
router.get('/', async (req, res) => {
console.log('*');
const { rows } = await db.all('SELECT * FROM users')
res.send(rows)
})
the index for this route at routes/index.js is simply:
const users = require('./user')
module.exports = (app) => {
app.use('/users', users)
}
and the db.query() and db.all() functions that I am awaiting are in db/index.js:
const { Pool } = require('pg')
const pool = new Pool()
module.exports = {
query: (text, params) => pool.query(text, params),
all: (text) => pool.query(text)
}
The routes are required in my main app.js file:
// ./app.js
const express = require('express')
const mountRoutes = require('./routes')
const cons = require('consolidate')
const path = require('path')
const bodyParser = require('body-parser')
const app = express()
mountRoutes(app)
// Assign Dust Engine to .dust files
app.engine('dust', cons.dust);
// Set .dust as the default extension
app.set('view engine', 'dust');
app.set('views', __dirname + '/views');
// Set Public Folder
app.use(express.static(path.join(__dirname, 'public')));
//Body parser and Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.get('/', function(reg, res) {
console.log('Root');
res.render('index', {hallo:'test'})
});
//Server
app.listen(3000, function() {
console.log('Server Started on Port 3000');
});
So far this works beautifully! I get the JSON strings that I want and I can build upon this sort of API by extending my routes and queries.
Question:
How can I return my JSON object rows back to app.js to res.render() it there?
or
Can I do something like this anywhere in my app:
jsonVar = GetMyJson('/users/1');
console.log(jsonVar);
returns:
[
{
"id": 1,
"usr_name": "Michael"
},
{
"id": 2,
"usr_name": "Thomas"
},
{
"id": 3,
"usr_name": "Paul"
}
]
I could then pass whatever route and parameters I want into GetMyJson() and deal with the resulting JSON.
This may be a trivial question for javascript devs ...
Thanks!
EDIT 21/12/2017
I have created a frontend script called graphs.js that simply logs my result when i call the fuction api('/user/1').
var el = document.getElementById("clickMe");
if (el.addEventListener)
el.addEventListener("click", api, false);
else if (el.attachEvent)
el.attachEvent('onclick', api);
var api = function(what){
// Action
sendRequest(what, function(result){
if(result){
log(result);
}
})
}
var apiEndpoint = 'http://localhost:3000/'
function sendRequest(_path, cb) {
var oReq = new XMLHttpRequest();
oReq.open('GET', apiEndpoint+_path);
oReq.onreadystatechange = function() {
if (this.readyState === 4) {
cb(JSON.parse(this.response));
}
else{
cb(null);
}
}
oReq.send();
}
function log(msg){
console.log(msg);
}
BUT
Is that a proper way of doing it in javascript?
The way to go about it would be something like this:
router.get('/', async (req, res) => {
console.log('*');
const { rows } = await db.all('SELECT * FROM users')
res.render('user', rows)
});
Instead of res.send you do res.render
You have to get it from database. Making self call will not be an ideal solution. So you can do following
const db = require('../db') // fix the location of db.js
app.get('/', function(req, res) {
db.all('SELECT * FROM users').then(function({ rows }) {
res.render('index', rows)
})
})
Best would be to make an userRepository.js and add code related to db over there. Then use that repository at both places.