Trying to use express middleware to serve third party API requests - express

Sorry if I posted this incorretly, it is my first question on Stack Overflow. I am currently trying to use express to serve third party API requests to my React front-end. This is because the steam api I use throws me a CORS error when requesting in the client-side. I tried to route the requests to my controller which makes the axios call, but I have had no luck. Not sure if I am doing something completely incorrect.
here is my server.js
const app = require('./app.js');
const PORT = process.env.PORT || 3005;
app.listen(PORT, () => console.log(`Listening on port: ${PORT}`))
and here is my app.js
const express = require('express');
const cors = require('cors')
const app = express();
app.use(cors())
module.exports = app
my routes:
const { Router } = require('express')
const controllers = require('../controllers')
const router = Router()
router.get('/', (req, res) => res.send('This is root!'))
router.get('/applist', controllers.getAllSteamGames)
router.get('/game/:id', controllers.getSingleGameSteam )
router.get('/gameSpy/:id', controllers.getSingleGameSpy)
module.exports = router
and lastly my controller:
const axios = require('axios');
const getAllSteamGames = async () => {
try {
const resp = await axios.get('https://api.steampowered.com/ISteamApps/GetAppList/v2?applist')
return resp.data
} catch (error) {
console.log(error)
throw error
}
}
Thank you for your help and time.

You aren't doing anything to send a response back to the client. If we look at the /applist route:
router.get('/applist', controllers.getAllSteamGames)
const axios = require('axios');
const getAllSteamGames = async () => {
try {
const resp = await axios.get('https://api.steampowered.com/ISteamApps/GetAppList/v2?applist');
return resp.data
} catch (error) {
console.log(error)
throw error
}
}
All, your getAllSteamGames() function does is return a promise that resolves to a value (remember all async functions return a promise). It doesn't send a response back to the client.
Then, if you look at the actual route handler, it doesn't send a response back to the client either. So, you get the request and never send a response. The client never gets a response.
What I would suggest is that you just send a response in your controller. It's already passed (req, res) as arguments to the function so you can use them.
router.get('/applist', controllers.getAllSteamGames)
const axios = require('axios');
const getAllSteamGames = async (req, res) => {
try {
const resp = await axios.get('https://api.steampowered.com/ISteamApps/GetAppList/v2?applist');
res.json(resp.data);
} catch (error) {
// send error status upon error
console.log(error);
res.sendStatus(500);
}
}

Related

Nextjs not able to receive data from expressjs API in correct format

ive got a page which i call an api through getserversideprops to basically get all the data from a table. it used to work fine, but suddenly when i runned it today an error occured which i dont know the cause is. this is the response im getting when i console log the response
what i tried on my own and noticed to "help" was reducing the amount of columns that the API was selecting. For the api i used knex and express. this was the original code that used to work but now does not.
try{
let data = "";
await db.transaction(async (t)=>{
data = await db('sales').transacting(t)
.join('users','users.id','sales.cashier_id')
.join('customer','customer.customer_id','sales.customer_id')
.select('customer.name as customer_name','sales.sales_id','sales.date','sales.payment_type','sales.payment_status','sales.customer_id','sales.transaction_total','sales.total_paid','users.name','sales.shipment_fee','sales.days','sales.sale_type')
})
return data
}catch(e){
console.log(e);
throw e;
}
what i tried was reducing the amount of select columns to i think 5 or 6, but definitely if the amount of columsn i use is under a limit it works. like
try{
let data = "";
await db.transaction(async (t)=>{
data = await db('sales').transacting(t)
.join('users','users.id','sales.cashier_id')
.join('customer','customer.customer_id','sales.customer_id')
.select('customer.name as customer_name','sales.sales_id','sales.transaction_total','sales.date','sales.payment_type')
})
return data
}catch(e){
console.log(e);
throw e;
}
these are the attributes of my table
this is the server.js file of my expressjs
const compression = require('compression');
const express = require("express");
const app = express();
const fs = require('fs');
const http = require('http')
const https = require('https')
const PORT = process.env.PORT || 8000;
var cors = require('cors')
const mainRoutes = require('./api/v1/routes/index')
const cookieParser = require("cookie-parser");
app.use(compression());
app.use(cors( {origin: 'http://localhost:3000',credentials: true}))
// app.use(cors());
app.use(express.json());
// app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
// Main Routes
app.use("/api/v1", mainRoutes,(req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
this is how im calling the api from next
export async function getServerSideProps(context) {
try{
const res = await axios.get("/sales/get-all");
const data = await res.data
return { props: { data } }
}catch(err){
const data = "error"
return { props: { data} }
}
}
where i declared default url of the axios at the app.js file of next
import '../styles/globals.css'
import axios from 'axios';
axios.defaults.baseURL = "http://localhost:8000/api/v1/"
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
im not quite sure what the problem is so pardon if the title of the question is not according to the problem i have.
EDIT:
i moved the api to a useeffect call, its now working. but why isnt it working in getserversideprops?

How to emit an event in express js and handle it in discord.js

I have a simple express.js backend that handles a get request from discord which runs a heavy process in the background using bull and throng.
I got it all working, Discord sends the get request. backend reserves the request and adds it to the job queue, once it's done I receive the returned value in the Queue.on() listener.
My problem is how can I send this result I get in the queue.on() listener back to discord as a message. how can I make discord listen to this event and post the result?
Note: discord and express are 2 separate apps. can't integrate them into one project.
Index.js file:
const express = require('express')
const scrapTikTok = require('./tiktokScraping')
const Queue = require('bull')
const app = express()
// Initialize BULL
const REDIS_URL = process.env.REDIS_URL || 'redis://127.0.0.1:6379'
const workQueue = new Queue('work', REDIS_URL, {
defaultJobOptions: {
removeOnComplete: true,
removeOnFail: true
}
})
app.get('/scrap', async (req, res) => {
res.send('Working on it...')
await scrapTikTok()
})
app.get('/url', async (req, res) => {
const url = 'https://www.tiktok.com/#tristanvincentt'
let job = await workQueue.add({url: url})
res.json({id: job.id})
})
workQueue.on('global:completed', (jobId, result) => {
console.log(`Job completed with result ${result}`)
// SEND RESULT BACK TO DISCORD
})
app.listen(process.env.PORT || 3000, () => {
console.log('App is running...')
})
Worker file:
const throng = require('throng')
const Queue = require("bull")
const REDIS_URL = process.env.REDIS_URL || "redis://127.0.0.1:6379"
const workers = process.env.WEB_CONCURRENCY || 1
const maxJobsPerWorker = 50
const sleep = ms => new Promise(r => setTimeout(r, ms));
function start() {
const workQueue = new Queue('work', REDIS_URL)
workQueue.process(maxJobsPerWorker, async job => {
console.log(job.data.url)
await sleep(10000)
return {value: job.id}
})
}
throng({workers, start})
you can create another express server in your discord app. and add a post endpoint:
const express = require('express')
const app = express()
app.post('/secreturl', async (req, res) => {
res.send('Discordjs Received the data!')
let jobId = req.body.jobId
let result = req.body.result
//now you have the results here!
})
then when the queue is done (based on the code you provided):
workQueue.on('global:completed', (jobId, result) => {
console.log(`Job completed with result ${result}`)
// SEND RESULT BACK TO DISCORD:
axios.post('(your-discordjs-server-ip)/secreturl', {
jobId: jobId,
result: result
})
})
just make sure you add the axios package to the queue app
npm install axios
and require it in the index.js file
const axios = require("axios")
tick this as the answer if it solved your problem!

router.route() doesnt want to work at all

I am trying to run router.route() with the following code
const express = require('express');
const app = express();
const router = express.Router();
router.route('/test').get(function (req, res, next) {
res.send('You have reached localhost:9000/test');
next();
});
app.listen(9000, () => {
console.log('Running on port 9000');
});
But it doesn't seem like anything is happening at all. Regardless of what I do, localhost:9000/test will not return anything Cannot GET /test. I don't understand what I'm doing wrong. Thanks in advance
You have to hook the router into your app with app.use():
const express = require('express');
const app = express();
const router = express.Router();
router.get('/test', function (req, res, next) {
res.send('You have reached localhost:9000/test');
});
app.use(router); // <=== add this
app.listen(9000, () => {
console.log('Running on port 9000');
});
Your original code creates a router object, but that router object is not hooked up to any web server yet. Using app.use(), you can hook it up to your web server so that it actually gets a chance to see the incoming requests.
Also, do not call next() after you call res.send(). Pick one of the other. Once you send a response, you do not want to continue routing to other routes because that will often try to then send another response, but you can only send one response to a given incoming http request.
You can simply use the Router().get(...) function instead.
The <Router>.get('/path', function() {...}); function will listen for incoming traffic to the path /path and then fire the callback function with the parameters request, response and next.
Example:
router.get('/test', function (req, res) {
res.send('You have reached localhost:9000/test');
});
Full example:
const express = require('express');
const app = express();
const router = express.Router();
router.get('/test', function (req, res) {
res.send('You have reached localhost:9000/test');
});
app.listen(9000, () => {
console.log('Running on port 9000');
});
Note: Using the next() function after sending a response to an incoming HTTP request will result in an error.

Nuxt/Express API is returning in console but not browser

I'm quite new to this whole backend business and I'm wondering if anyone can see where I'm going wrong. I've got an express server in my Nuxt app which is serving out an API. When I run the localhost:3000/api/salesforce/:id route - my vscode terminal generates a response - but it doesn't show up on the browser. Which in turn makes it inaccessible to Nuxt.
In my nuxt.config.js:
serverMiddleware: {
'/api': '~/api'
},
/api/index.js:
const express = require('express')
// Create express instance
const app = express()
// Require API routes
const users = require('./routes/users')
const test = require('./routes/test')
const salesforce = require('./routes/salesforce')
// Import API Routes
app.use(users)
app.use(test)
app.use(salesforce)
// Export express app
module.exports = app
// Start standalone server if directly running
if (require.main === module) {
const port = process.env.PORT || 3001
app.listen(port, () => {
// eslint-disable-next-line no-console
console.log(`API server listening on port ${port}`)
})
}
Then in /api/routes/salesforce.js:
const e = require('express')
const { Router } = require('express')
const router = Router()
const jsforce = require('jsforce');
// require the .env file for login
require('dotenv').config();
const { SF_USERNAME, SF_PASSWORD, SF_TOKEN, SF_LOGIN_URL } = process.env;
if (!(SF_USERNAME && SF_PASSWORD && SF_TOKEN && SF_LOGIN_URL)) {
console.error(
'Cannot start app: missing mandatory configuration. Check your .env file.'
);
process.exit(-1);
}
const conn = new jsforce.Connection({
loginUrl: SF_LOGIN_URL
});
conn.login(SF_USERNAME, SF_PASSWORD + SF_TOKEN, err => {
if (err) {
console.error(err);
process.exit(-1);
}
});
// get OPPORTUNITY specific
router.get('/salesforce/:id', function (req, res, next) {
const id = req.params.id
console.log(req.params.id)
const sfData = conn.query(`SELECT Id, Name, StageName FROM Opportunity WHERE Name = '` + id + `'`, (err, res)=>{
if(err){
console.log(err)
return "error";
} else {
console.log(res.records[0])
let sanitisedData = res.records[0]
return sanitisedData;
}
})
res.json(sfData.json)
})
If anyone can tell me where I'm going wrong that would be greatly appreciated, I'm kind of stuck here.

Run socket.io from an express route

I have researched on this but nothing seems to satisfy my need. I have an express route connected to a mongodb. Below is part of the code.
const express = require('express');
const socketIo = require("socket.io");
const dbconnect = require("./models");
const handle = require("./handlers");
const routes = require("./routes");
const app = express();
app.use('/messages', routes.messages);
const PORT = 3000;
const server = app.listen(3000, function() {
console.log(`Listening on 3000`);
dbconnect().then(() => {
console.log("MongoDb connected");
});
});
const io = socketIo(server);
io.on('connection', function(client) {
console.log('Connected...');
});
My route looks like this:
const router = require('express').Router();
const handle = require('../handlers/messages');
router.post('/unread_messages', handle.unread_messages);
module.exports = router;
My handler looks like this:
const db = require("../models");
exports.unread_messages = async (req, res, next) => {
try {
const unreadmessages = await db.messages.countDocuments({ $and: [{receiver: req.body.receiver},
{ messageread: false }]});
return res.json({ unreadmessages });
} catch (err) {
return next({ status: 400, message: `Cannot get unread messages ${err}` });
}
};
I would like to add socket to the "/unread_messages" route so that I get an update of the count of unread messages in realtime. How do I do that?