unable to call and manipulate external api in node js using request - javascript

I am trying to call [https://jsonplaceholder.typicode.com/albums/1/photos] in my node codes so that i create an end-point that is dynamic...like if i change 1 in url i get the relevant photos.
here are my codes
const request = require('request');
const callExtrenalApiUsingRequest = async (callback, req, res) => {
try {
let id = req.params.id
await request(`https://jsonplaceholder.typicode.com/albums/${id}/photos`, { json: true }, (err, res, body) => {
if (err) {
return callback(err);
}
return callback(body)
})
}
catch (error){
console.log(error)
}
}
module.exports.callApi = callExtrenalApiUsingRequest;
request.js
const apiCallFromRequest = require( './request.js');
const http = require('http')
http.createServer((req, res) => {
try {
if (req.url === "/request/photos/:id") {
apiCallFromRequest.callApi(function (response) {
res.write(JSON.stringify(response));
res.end();
})
}
}
catch (err) {
console.log(err)
}
}).listen(3000)
console.log("service running on port 3000...")

Related

Middleware is breaking redis / express setup

I'm using redis for the first time, and I can't quite figure out why my middleware 'cache' function is breaking my code? It works great without it, displays in the browser, if I go to my terminal and check for a key value pair it works great.
Here is my setup:
const express = require("express");
const redis = require("redis");
const axios = require("axios").default;
const PORT = process.env.PORT || 5000;
const REDIS_PORT = process.env.PORT || 6379;
const client = redis.createClient(REDIS_PORT);
client.connect();
const app = express();
function setResponse(username, repos) {
return `<h2>${username} has ${repos} Github repos</h2>`;
}
// make req to github
async function getRepos(req, res, next) {
try {
console.log("fetching data...");
const { username } = req.params;
const response = await axios.get(
`https://api.github.com/users/${username}`
);
const data = response.data;
const repos = data.public_repos;
// set to redis
client.set(username, repos);
res.send(setResponse(username, repos));
} catch (err) {
console.log(err);
res.status(500);
}
}
// Cache middleware
function cache(req, res, next) {
const { username } = req.params;
client.get(username, (err, data) => {
if (err) throw err;
if (data !== null) {
res.send(setResponse(username, data));
} else {
next();
}
});
}
app.get("/repos/:username", cache, getRepos);
app.listen(5000, () => {
console.log(`App listening on port ${PORT}`);
});
Any advice would be much appreciated!
Your cache function
function cache(req, res, next) {
const { username } = req.params;
client.get(username, (err, data) => {
if (err) throw err;
if (data !== null) {
res.send(setResponse(username, data));
} else {
next();
}
});
}
uses node redis 3 "logic" so it's hanging
redis 4 is promise led, so you need to use async/await or .then/.catch
So something like this should work for the .then/.catch approach
// Cache middleware
function cache(req, res, next) {
console.log('caching for', req.params);
const { username } = req.params;
client.get(username)
.then((data) => {
if (data !== null) {
res.send(setResponse(username, data));
} else {
next();
}
})
.catch(err => {
if (err) throw err;
});
}
This will solve your initial problem of "why it's getting stuck"

Node Express- delete route works but throws an error

I made an api app in Node Express. Routes post and put are working perfectly. Delete route is also working but I dont see confirmation of resolved promise, instead after few secs I see those errors
Access to XMLHttpRequest at 'https://ahi' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
PageAdmin.js:179 fail Error: Network Error
DELETE https://ahi net::ERR_FAILED
I was already dealing with that problem at beginning of setting up app on server so I searched how to deal with it. Here is my middleware code on server for setting up headers
function setHeaders(app) {
app.use(function (req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, OPTIONS, PUT, PATCH, DELETE"
);
res.setHeader(
"Access-Control-Allow-Headers",
"Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Allow-Origin, Access-Control-Allow-Methods, x-auth-token"
);
res.setHeader("Access-Control-Allow-Credentials", true);
// handle OPTIONS method
if ("OPTIONS" == req.method) {
return res.sendStatus(200);
} else {
next();
}
});
}
Here is the code for routes
const express = require("express");
const router = express.Router();
const mongoose = require("mongoose");
const auth = require("../middleware/auth");
const { ProgrammingTool, validate } = require("../models/programmingTool");
const msg400 = "Bad request";
const msg400InData = "Item already exists in database";
const msg404 = "Could not find item in database";
const msg500 = "Something went wrong";
router.get("/", async (req, res) => {
try {
const tools = await ProgrammingTool.find();
res.send(tools);
} catch (e) {
console.log("failed getting tools", e);
res.status(500).send(msg500);
}
});
router.get("/:id", async (req, res) => {
if (!mongoose.Types.ObjectId.isValid(req.params.id))
return res.status(404).send(msg404);
const tool = await ProgrammingTool.findById(req.params.id);
if (!tool) return res.status(404).send(msg404);
res.send(tool);
});
router.post("/", auth, async (req, res) => {
const validation = validate(req.body);
if (validation.error) return res.status(400).send(msg400);
try {
const toolInData = await ProgrammingTool.findOne({ name: req.body.name });
if (toolInData) return res.status(400).send(msg400InData);
} catch (e) {
return res.status(500).send(msg500);
}
const tool = new ProgrammingTool({ name: req.body.name });
try {
await tool.validate();
} catch (e) {
console.log("did not pass mongoose validation at posting", e);
return res.status(400).send(msg400);
}
try {
const result = await tool.save();
res.send(result);
} catch (e) {
console.log("failed to post tool");
res.status(500).send(msg500);
}
});
router.delete("/:id", auth, async (req, res) => {
const id = req.params.id;
let tool;
try {
tool = await ProgrammingTool.findById(id);
} catch (e) {
console.log("could not find the tool with provided id", e);
res.status(404).send(msg404);
}
try {
await tool.delete();
} catch (e) {
console.log("failed deleting tool", e);
res.status(500).send(msg500);
}
});
router.put("/:id", auth, async (req, res) => {
const validation = validate(req.body);
if (validation.error) return res.status(400).send(msg400);
const id = req.params.id;
const tool = await ProgrammingTool.findById(id);
if (!tool) res.status(404).send(msg404);
tool.name = req.body.name;
try {
await tool.validate();
} catch (e) {
console.log("did not pass mongoose validation at putting", e);
return res.status(400).send(msg400);
}
try {
const result = await tool.save();
res.send(result);
} catch (e) {
console.log("failed to save edited tool");
res.status(500).send(msg500);
}
});
router.delete("/", auth, (req, res) => {
res.status(400).send(msg400);
});
router.put("/", auth, (req, res) => {
res.status(400).send(msg400);
});
What really suprises me is that the error is getting thrown but route does it job, item is deleted from database.
In the delete route there are 2 problems.
you are not using return so even after the first error it goes to the second try catch block. Add return to both res.status(..).send(..)
For a successful Delete operation you are not returning a 2xx status code. So if there is a successful deletion the request will be stuck cause you are not returning anything, after some time probably it will time out.

Node JS PATCH request running no matter what

Sorry if the title if confusing, I wasn't too sure how to word it. I have a PATCH request to update a value in my database, but even though it is "working" (200 status), it's not actually.
I have a .route('/:movie_id/:user_id').all() handler to trigger for all my methods, where it pulls a movie from the database by movie_id and user_id. This works. Then I move on to my PATCH request, but it seems like the PATCH request isn't actually running. I am getting the correct response from the .all() handler, but no update is happening. Even if I completely comment out the code for my PATCH, I am still getting a 200 status.
Here is my .all() handler with my PATCH request:
movieRouter
.route('/:movie_id/:user_id')
.all(requireAuth)
.get((req, res, next) => {
const db = req.app.get('db')
MovieService.getById(db, req.params.movie_id, req.params.user_id)
.then(movie => {
if(!movie) { // this runs fine
return res.status(404).json({ error: `Movie doesn't exist`})
}
// res.json({movie : movie}); --> old code
// solution:
res.movie = movie;
next();
return movie;
})
.catch(next)
})
.patch(requireAuth, (req, res, next) => {
const db = req.app.get('db')
const { watched } = req.body
const updatedMovie = { watched }
// this doesn't run
const numVal = Object.values(updatedMovie).filter(Boolean).length
if(numVal === 0) {
return res.status(400).json({ error: `Must not be blank`})
}
MovieService.updateMovie(db, req.params.movie_id, req.params.user_id, updatedMovie)
.then(movie => {
res.status(200).json(updatedMovie)
})
.catch(next)
})
Here is my MovieService:
updateMovie(db, movie_id, newMovie) {
return db('your_movie_list').where('id', movie_id).where('user_id', user_id).update(newMovie).returning('*')
}
It should be the problem of the 2nd .all(), .all() will catch all request, no matter it is GET, POST, PATCH, DELETE. So even when you comment out PATCH code, it will return 200.
Change the 2nd .all to .get like below
app.use(express.json())
movieRouter
.route('/:movie_id/:user_id')
.all(requireAuth)
.get((req, res, next) => { // use .get instead of .all to avoid catching all requests
const db = req.app.get('db')
MovieService.getById(db, req.params.movie_id, req.params.user_id)
.then(movie => {
if(!movie) { // this runs fine
return res.status(404).json({ error: `Movie doesn't exist`})
}
res.json({movie : movie});
})
.catch((e) => {
console.log("From getMovie", e);
res.status(400).json({ error: e.message })
})
})
.patch((req, res, next) => {
try {
const db = req.app.get('db')
const { watched } = req.body
const updatedMovie = { watched }
// this doesn't run
const numVal = Object.values(updatedMovie).filter(Boolean).length
if(numVal === 0) {
return res.status(400).json({ error: `Must not be blank`})
}
MovieService.updateMovie(db, req.params.movie_id, req.params.user_id, updatedMovie)
.then(movie => {
console.log(movie) // nothing logs
res.status(200).json(movie[0])
})
.catch((e) => {
console.log("From updateMovie", e);
res.status(400).json({ error: e.message })
})
}catch(e) {
console.log("From try/catch", e);
res.status(400).json({ error: e.message })
}
})
A little working example for cross-checking
const express = require("express");
const app = express();
const PORT = process.env.PORT || 8080;
app.use(express.json())
const movieRouter = express.Router()
movieRouter
.route('/:movie_id/:user_id')
// .all(requireAuth)
.get((req, res, next) => {
res.json({"movie:get" : 1});
})
.patch((req, res, next) => {
res.json({"movie:patch" : 1});
})
app.use(movieRouter)
app.listen(PORT, function (err) {
if (err) console.log(err);
console.log("Server listening on PORT", PORT);
});

How do you nest routes in express?

I am new to express and node and I have this situation:
controller:
exports.find_by_IDN_post = (req, res) => {
console.log('init')
accidentDetail.findOne({ idn: req.body.idn }, (err, data) => {
if (err) {
res.status(500).send(err)
}
console.log(data)
res.status(200).send(data)
})
}
exports.find_by_name_post = (req, res) => {
accidentDetail.findOne({$or: [{'firstName': req.body.name}, {'middleName': req.body.name}, {'surname': req.body.name}]}, (err, data) => {
if (err) {
res.status(500).send(err)
}
res.status(200).send(data)
})
}
exports.find_by_date_post = (req, res) => {
accidentDetail.findOne({firstReg: req.body.firstReg}, (err, data) => {
if (err) {
res.status(500).send(err)
}
res.status(200).send(data)
})
}
exports.find_by_accident_type_post = (req,res) => {
accidentDetail.findOne({accidentType: req.body.accidentType}, (err, data) => {
if (err) {
res.status(500).send(err)
}
res.status(200).send(data)
})
}
route:
const express = require('express')
const router = express.Router()
const query_controller = require('../controllers/QueryController')
router.post('/idn', query_controller.find_by_IDN_post)
router.post('/name', query_controller.find_by_name_post)
router.post('/date', query_controller.find_by_date_post)
router.post('/accidentType', query_controller.find_by_accident_type_post)
module.exports = router
app
const queryRouter = require('./routes/query')
app.use('/query', queryRouter)
How do I nest the routes? I want to be able to access the routes like this:
localhost:3001/query/idn
localhost:3001/query/name
...
At the moment, I can't receive the console.log('init') when trying to access localhost:3001/query/idn.

NodeJs - TypeError: Cannot read property 'url' of null, but the app is working fine

UPDATE: I it checks for /:slug even if i go to a different route, i think thats causing the problem.
I'm trying to create a URL Shortener with Nodejs, Expressjs, MongoDB and EJS.
Even though my application is working perfectly, I keep getting this error in terminal:
My routes :
const express = require("express");
const URLs = require("../models/urls");
const { findById, find } = require("../models/urls");
const router = express.Router();
router.get("/", (req, res) => {
res.render("index", { shortUrl: new URLs() });
});
router.post("/redirect", (req, res) => {
let url = req.body.url;
let slug = req.body.slug;
let shortenUrl = new URLs({
url: url,
slug: slug,
});
shortenUrl.save();
res.render("shortenUrl", { shortenUrl });
});
router.get("/about", (req, res) => {
res.render("about");
});
router.get("/contact", (req, res) => {
res.render("contact");
});
router.get("/all", async (req, res) => {
try {
var shortUrls = await URLs.find({});
res.render("all", { shortUrls });
} catch (error) {
console.log(error);
}
});
//:TODO
router.get("/:slug", async (req, res) => {
var shortUrl = await URLs.findOne({ slug: req.params.slug }).exec();
try {
console.log(shortUrl);
var urls = await shortUrl.url;
if (urls.includes("http", 0)) {
return res.redirect(urls);
} else {
return res.redirect(`http://${urls}`);
}
} catch (error) {
console.log(error);
}
});
module.exports = router;
I didn't get this error until I made API for the app (in separate routes file).
Also in my server I'm using:
app.use(bodyParser.urlencoded({ extended: false }));
and using:
app.use(express.json());
doesn't help either.
Any help would be appreciated, Thank you c:
I added an if statement to the route and that solved the problem, thanks to #Pukka c:
router.get("/:slug", async (req, res) => {
var shortUrl = await URLs.findOne({ slug: req.params.slug }).exec();
if (shortUrl) {
try {
console.log(shortUrl);
var urls = await shortUrl.url;
if (urls.includes("http", 0)) {
return res.redirect(urls);
} else {
return res.redirect(`http://${urls}`);
}
} catch (error) {
console.log(error);
}
}

Categories