How to get full dynamic URL with expressJS - node.js

I'm building a middleware to check acl, but I cannot find a way to get the URL of dynamic routes. Example : '/user/:id/movie/:name'. I'm able to get the url but it's already filled with the id and name, how can I get the raw URL for this dynamic routes ? (I already checked baseUrl, originalUrl, url)

So express doesn't know what is the end dynamic URL due to router. Each route can be appended to any URL prefix.
in your case:
user/:id - is the prefix
movie/:name - is the route
const express = require('express')
const app = express()
const port = 3000
// add empty urlTemplate on each incoming request
app.use((req, res, next) => {
req.urlTemplate = "";
next();
});
// create route
var router = express.Router()
const urlTemplateMove = '/movie/:name';
const moveRoute = router.get(urlTemplateMove, function (req, res) {
req.urlTemplate += urlTemplateMove; // <- append current route urlTemplate
console.log(req.urlTemplate);
res.json(req.urlTemplate);
});
// append urlTemplate on each route
const urlTemplateUser = '/user/:id';
app.use(urlTemplateUser, (req, res, next) => {
req.urlTemplate += urlTemplateUser;
moveRoute(req, res, next);
});
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`));
Note if you're not interested in using router you just create the URL as in a higher scope and then you will have access to it in the callback.
const express = require('express')
const app = express()
const port = 3000
const urlTemplate = '/user/:id/movie/:name';
app.get(urlTemplate, function (req, res) {
console.log(urlTemplate);
res.json(urlTemplate);
});
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`));

Related

Transform NextJs output into JSON using ExpressJs

For migration purposes I have to transform the content generated by nextjs into JSON format like {content: "generated markup"} in expressjs.
const express = require('express');
const next = require('next');
const port = 8080;
const dev = process.env.NODE_ENV !== 'production';
const nextApp = next({dev});
const handle = nextApp.getRequestHandler();
nextApp.prepare().then(() => {
const server = express();
server.all('*', async (req, res) => {
return handle(req, res);
});
server.use((req, res, next) => {
/* How to set res.json({content:<RESULT_FROM_NEXT_JS>})??? */
});
server.listen(port, () => {
console.log(`[server]: Server is running at http://localhost:${port}`);
});
});
What I understand so far is that next creates a stream of chucked data but I do not know how to block this stream to then create a json from it. Any clue on how to build a middleware for that? Or any other idea on how to generate a JSON in this format?

Returning data to a user from an external API

i am trying to return the value of my search after using the node-spotify-api package to search for an artist.when i console.log the spotify.search ..... without the function search function wrapped around it i get the values on my terminal..what i want is when a user sends a request to the userrouter routes i want is to display the result to the user..i using postman for testing ..
This is the controller
const Spotify = require('node-spotify-api');
const spotify = new Spotify({
id: process.env.ID,
secret: process.env.SECRET,
});
const search = async (req, res) => {
const { name } = req.body;
spotify.search({ type: 'artist', query: name }).then((response) => {
res.status(200).send(response.artists);
}).catch((err) => {
res.status(400).send(err);
});
};
module.exports = {
search,
};
**This is the route**
const express = require('express');
const searchrouter = express.Router();
const { search } = require('./spotify');
searchrouter.route('/').get(search);
module.exports = searchrouter;
**This is my server.js file**
const express = require('express');
require('express-async-errors');
const app = express();
require('dotenv').config();
// built-in path module
const path = require('path');
// port to be used
const PORT = process.env.PORT || 5000;
// setup public to serve staticfiles
app.use(express.static('public'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.set('port', PORT);
const searchrouter = require('./route');
app.use('/search', searchrouter);
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, 'index.html'));
});
app.listen(PORT, (req, res) => {
console.log(`Server is listening on port ${PORT}`);
});
[that is my project structure][1]
Well Your Code has a bug
Which is
searchrouter.route('/').get(search);
You are using a get request and still looking for a req.body
const { name } = req.body;
name is going to equal to = undefined
and when this runs
spotify.search({ type: 'artist', query: name })
it's going to return an empty object or an error
req.body is empty for a form GET request
So Your fix is
change your get request to a post
searchrouter.route('/').post(search);

Can't retrieve information from mongodb when deploying on heroku

The problem is as the title suggests. When I run my app locally, I'm able to retrieve information from MongoDB but on Heroku, undefined is returned. Should I connect to MongoDB in another way because if I hardcode some text everything works just fine. Here are my scripts:
function to get data
const MongoClient = require("mongodb").MongoClient;
const dbConnectionUrl = "mongodb+srv://xxxxxxx#cluster0.ro4dz.mongodb.net/data?retryWrites=true&w=majority";
const saySomething = (req, res, next) => {
// res.status(200).json({
// body: 'Hello from the server!'
// });
login()
.then(val=>res.send(val))
};
async function login(){
const client = new MongoClient(dbConnectionUrl)
try{
await client.connect();
const database = client.db("data");
const movies = database.collection("movies");
const query = { name: "toke" };
const movie = await movies.findOne(query);
return movie
}catch(err){
console.log(err)
}
}
module.exports.saySomething = saySomething;
router
const express = require('express');
const router = express.Router();
const controllers = require('./../controllers/controllers');
router.get('/say-something', controllers.saySomething);
module.exports = router;
server
// Import dependencies
const express = require('express');
const cors = require('cors');
const path = require('path');
// Create a new express application named 'app'
const app = express();
// Set our backend port to be either an environment variable or port 5000
const port = process.env.PORT || 5000;
// This application level middleware prints incoming requests to the servers console, useful to see incoming requests
app.use((req, res, next) => {
console.log(`Request_Endpoint: ${req.method} ${req.url}`);
next();
});
// Configure the CORs middleware
// Require Route
app.use(cors());
const api = require('./routes/routes');
// Configure app to use route
app.use('/api', api);
// This middleware informs the express application to serve our compiled React files
if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'staging') {
app.use(express.static(path.join(__dirname, 'client/build')));
app.get('*', function (req, res) {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});
};
// Catch any bad requests
app.get('*', (req, res) => {
res.status(200).json({
msg: 'Catch All'
});
});
// Configure our server to listen on the port defiend by our port variable
app.listen(port, () => console.log(`BACK_END_SERVICE_PORT: ${port}`));
front
import { useEffect, useState } from 'react';
import './App.css';
import axios from 'axios'
function App(){
useEffect(()=>{
get()
})
const[text, settext] = useState('')
async function get(){
let request = await axios.get('/api/say-something')
console.log(request.data.name)
settext(request.data.name)
}
return(
<div>{text}</div>
)
}
export default App;
I solved the issue! The first thing I did was that I added MongoDB connection URI as an environmental variable in my app via Heroku. Secondly, I added an option in MongoDB so that the cluster can be accessed from any computer. By default, the access is set to the local computer so I added another IP, namely 0.0.0.0/0 to my cluster, and now everything works just fine.

Expressjs server and external api calls

I'm new to frontend development and express server. When I tried to start an express.js server with react (with axios calls to external apis), it seems express.js is adding 'localhost:3000' in front of the external API calls so they fail.
In my server.js:
const path = require('path');
const express = require('express');
const app = express();
const publicPath = path.join(__dirname, '.', 'dist');
const port = process.env.PORT || 3000;
app.use(express.static(publicPath));
app.get('*', (req, res) => {
res.sendFile(path.join(publicPath, 'index.html'));
});
app.listen(port, () => {
console.log('Server is up!');
});
Which leads to the API call to www.example.com/api/ to become http://localhost:3000/www.example.com/api/
I also tried to filter the req by writing:
app.get('*', (req, res) => {
if (req.url.match(/\/api\//) === null) {
res.sendFile(path.join(publicPath, 'index.html'));
}
});
But it does not change things...
Can anyone help out this newbie that is me?
Update1 Adding the code for calling the api:
This is the api call:
const getSomething = () => {
try {
const url = endpoints.GET_SOMETHING;
return axios.get(url);
} catch (err) {
console.log(err);
}
};
endpoints.GET_SOMETHING is the api URL: www.example.com/api/getSomething
You need to put a / in the url
app.get('/*', (req, res) => {
res.sendFile(path.join(publicPath, 'index.html'));
});
and also your endpoint url should start with https://, http:// or //

Is there any possibility to use socket.io just for specific part of application?

I am pretty new in socket.io. Just I want to know is there any possibility to use socket for certain part of application and the rest continue working with normal http RESTful API?
To be more specific, I have develop an app with ionic 5 for frontend and nodejs, express and mongodb for backend.
I have added socket.io into my app.js file same as below and server is listening.
const app = express();
const port = process.env.PORT || 5000;
const http = require("http");
const server = http.createServer(app);
const io = require("socket.io")(server);
io.on('connection',(socket)=>{
console.log('a user connected')
socket.on('disconnect', function(){
io.emit('user-changed', {user:socket.username,event:'left'});
})
socket.on('comment',(comment)=>{
console.log(comment)
io.emit('comment',{cmt: comment.text,user:socket.username, createdAt: new Date()})
})})
My route file for discussion APIs
const express = require("express");
const router = require("express-promise-router")();
const discussionController = require("../controllers/discussion.controller");
const auth = require("../../helpers/auth");
router.route("/").get(discussionController.getAllDiscussions);
router.route("/discussion/:id").get(discussionController.getDiscussion);
router.route("/comment").post(auth, discussionController.createComment);
router.route("/comments/:id").get(auth, discussionController.getComments);
router.route("/search/:params").get(auth, discussionController.searchDiscussion);
router.route("/create-discussion").post(auth,discussionController.createDiscussion);
module.exports = router;
My controller file
const mongoose = require("mongoose");
const Discussion = require("../../models/discussion.model");
const Comment = require("../../models/comment.model");
module.exports = {
getAllDiscussions: async (req, res, next) => {},
getDiscussion: async (req, res, next) => {},
getComments: async (req, res, next) => {},
createDiscussion: async (req, res, next) => {},
createComment: async (req, res, next) => {},
searchDiscussion: async (req, res, next) => { }
};
Also in my app.module n front, I have added SocketIoModule and Config same as below.
import { SocketIoModule, SocketIoConfig } from 'ngx-socket-io';
const config: SocketIoConfig = { url: 'http://localhost:5000', options: {} };
So, everything is working fine and I can send and receive comment from discussion page too.
What I want is the possibility of opening socket just for discussion page not enitre app and also how can I integrated with my server side controller to save into database and retrieve it.

Resources