Node router returning response by itself - javascript

This is probably extremely simple but I am really confused by it.
When I hit my node /verify endpoint either via postman or the frontend, a 200 response from the backend is being sent back automatically when non 'response' values/functions are in the /verify endpoint.
For example, if I make the function extremely simple:
This will send a 200 response back, even though I don't appear to be setting 'response' anywhere.
router.post('/verify', (request, response, next) => {
code = code.toUpperCase();
});
This won't send a 200 response back (and I don't think it should, as I'm not setting response to anything)
router.post('/verify', (request, response, next) => {
const { code } = request.body;
console.log(code);
});
Can anyone explain to me what is going on? I expect to need to reference response like the examples below to push a response back
response.status(401).send("Lorem ipsum");
or
response.json(token);
Thanks
Whole page (excluding other API calls which shouldn't affect this)
const poolArray = require('../../db');
const { Router } = require('express');
const router = Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
router.post('/verify', (request, response, next) => {
// let { code } = request.body; //if commented out will send 200 back automatically, if not commented out won't pass 200 back automatically
code = code.toUpperCase();
})
module.exports = router;
My index.js:
const { Pool } = require('pg');
const oracledb = require('oracledb');
oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT;
const { langleyUser, langleyHost, langleyDatabase, langleyPassword, langleyPort, onboardingUser, onboardingHost, onboardingDatabase, onboardingPassword, onboardingPort } = require('../secrets/db_configuration');
const langley = new Pool({ user: langleyUser, host: langleyHost, database: langleyDatabase, password: langleyPassword, port: langleyPort });
const onboarding = new Pool({ user: onboardingUser, host: onboardingHost, database: onboardingDatabase, password: onboardingPassword, port: onboardingPort });
const poolArray = {
langley,
onboarding
}
module.exports = poolArray;
Middleware
const jwt = require('jsonwebtoken');
module.exports = (request, response, next) => {
try {
console.log(' in check auth request');
const decoded = jwt.verify(request.headers.authorization, 'bFm3Vp4Ga#cG6W');
request.userData = decoded;
next();
} catch (error) {
return response.status(404).json({
message: 'Authentication failed'
})
}
};

I believe Express will return 200 OK (?) when the response is not specified. If you want to continue to another middleware layer then call next().

Related

Integrate Nodejs Backend with React Frontend App

I am building an app that uses node.js for backend and react for frontend. In the backend, i have 2 functions that implement a post request.
In my react function:
I want to show a spinner while waiting for the response data from the API request.
For the triggerGrading function which only returns ok if successful, I want to be able to return a custom message in the frontend.
Here are my functions, and they work fine on postman. However, I am experimenting with NodeJS and React and want to know if there's any further logic I need to add to these backend functions to be able to accurately implement the spinner and a custom message return in the UI?
grading.js
const BASE_URL = htttp://localhost:8080
const postSubject = async (req, res, next) => {
const headers = {
"Score-API-Version": "v2",
"Content-type": "application/json",
};
const body = { name: 'Adam Lawrence' };
try {
const resp = await axios.post(`${BASE_URL}/subject`, body, { headers });
const response = resp.data;
res.send(response);
} catch (err) {
if (err.response) {
res.status(err.response.status).send(err.response.data);
} else if (err.request) {
res.send(err.request);
}
next(err);
}
};
const triggerGrading = async (req, res, next) => {
const { id } = req.params;
const headers = {
"Content-type": "application/json",
"Score-API-Version": "v2",
};
try {
const resp = await axios.post(`${BASE_URL}/start/${id}`, { headers });
const response = resp.data;
res.send(response);
} catch (err) {
if (err.response) {
res.status(err.response.status).send(err.response.data);
} else if (err.request) {
res.send(err.request);
}
next(err);
}
};
server.js
const express = require("express");
const flows = require("./grading.js");
const cors = require("cors");
const app = express();
app.use(cors());
const PORT = 5050;
app.use(express.json());
app.listen(PORT, () => {
console.log(`Running this application on the PORT ${PORT}`);
});
app.post("/subject", grading.postSubject);
React query is very easy comfy, but if you just want to explore a little bit on your own you can play with this example in codepen.
In order to show a spinner while the request is being made you can use useState:
const handleClickSpin = async()=>{
setIsLoading(true)
await postSubject()
setIsLoading(false)
}
and then conditionally show the spinner.
For the second part of your question, I assumed you didn't want to send the custom message from your sever, so I just added another flag with conditional rendering.

Using express-formidable to get multipart data , but it makes simple post requests with request body run forever

app.js
const express = require('express')
const app = express()
const app = express()
const PORT = process.env.SERVER_PORT || 8080
app.use(express.json())
app.use(express.urlencoded({
extended : true
}))
app.use(formidableMiddleware());
app.listen(PORT, () => {
console.log(`The application is up and running on ${PORT}`)
})
controller.js
This contains the controller that takes base64 encoded image in formdata and that can be accessed with filename property (This is one controller which is working fine with formidable)
const uploadProfilePic = async (req, res) => {
let strArr = req.fields.filename.split(',')
let buffer = new Buffer(strArr[1], 'base64')
let filename =
Date.now().toString() + '' + strArr[0].split('/')[1].split(';')[0]
try {
req.user.profile = buffer
req.user.filename = filename
await req.user.save()
return res.status(200).json(
customMessage(true, {
message: 'Successfully uploaded',
}),
)
} catch (error) {
return res.status(500).status(internalServerError)
}
}
controller2.js This controller is not working properly, it does not even run when we use express-formidable and the post request route to which this controller is binded to, runs forever, but if we pass no request body then it runs perfectly or if we comment out:
//app.use(express-formidable);
//In app.js
then it runs properly but then controller.js doesnt run.
const updateUserData = async (req, res) => {
try {
const {_id, email, name, username, bio, code, platform, languages } = req.body
if (username === undefined || code === undefined || !platform || !languages)
return res
.status(400)
.json(customMessage(false, 'Please Satisy Validations'))
let user = req.user
let user1 = await UserModel.findById(_id)
user1.username = username;
user1.code = code;
user1.bio = bio;
user1.platform = platform;
user1.languages = languages;
if (!user) return res.status(500).json(internalServerError())
else {
await user1.save()
console.log
return res
.status(200)
.json(customMessage(true, `user with ${email} updated`))
}
} catch (error) {
console.log(error)
return res.status(500).json(internalServerError())
}
}
Okay I found a way to send requests through the multipart/form data and the application/json without breaking any thing. I actually spent 2 hours trying to figure out what happened and how to solve the problem. I discovered that the package "express-formidable" is no longer being maintained and has been closed down. Then I also found another package which of course solved the problem just about now "express-formidable-v2" which I believe is the continuation of the former package.
Check this https://github.com/Abderrahman-byte/express-formidable-v2 out, It is a fork of "express-formidable" package
Now you have access to your {req.fields} and {req.body}

Axios post request failing with a 404

I'm using Axios to query an endpoint in my backend. When I try and do this, I get a 404 not found. If I copy/paste the uri it gives in the error from the console and try and access it directly in the browser it connects fine and does not give me an error (instead giving me an empty object which is expected).
Below is my Axios code
axios.post("/api/myEndpoint", { id: this.userID })
.then((response) => {
this.property = response.data.property;
})
.catch((errors) => {
console.log(errors);
router.push("/");
});
Below is the route definition in my backend
const myEndpointRoute = require('../api/myEndpoint.js')();
exprApp.use('/api/myEndpoint', myEndpointRoute);
For reference, the uri is 'http://localhost:3000/api/myEndpoint'. I can access this uri completely fine in the browser but Axios returns a 404 as described above. It is for this reason that I'm confident this is an issue in the frontend, however I have set up this Axios request in the same way as the many others I have and they all work fine.
Edit: here's the rest of the backend
myEndpoint.js
module.exports = function() {
const express = require('express'), router = express.Router();
const authMiddleware = require('../loaders/authMiddleware.js')();
router.get('/', authMiddleware, async function(req, res) {
const id = req.body.id;
const property = await require('../services/myEndpointService.js')
(id).catch((e) => { console.log(e) });
res.send({ property: property });
});
return router;
};
myEndpointService.js
module.exports = async function(id) {
const results = await require('../models/getMyEndpointProperty')(id);
return results;
};
getMyEndpointProperty
module.exports = async function(id) {
const pool = require('../loaders/pool.js')();
const res = await pool.query(`SELECT * FROM myTable WHERE id = ${id};`);
return res.rows;
};
myEndpoint.js defines only a GET method but your axios call sends a POST in the frontend. Try changing (or adding) the express route:
// notice the `.post`
router.post('/', authMiddleware, async function(req, res) {
...
})
It worked when you manually tested it in the browser for this reason as well, since the browser sent a GET request.

Unit Testing Controllers use Jest, NodeJS

I want to check a case that certain routes are calling the correct controller use Jest specific (mock or spy).
It is case specific for unit testing. Somebody can help me how to check it use jest. I don't need verify kind of
expect (status code or res object) i need to check if controller have been called.
Thanks!
For instance:
// todoController.js
function todoController (req, res) {
res.send('Hello i am todo controller')
}
// index.spec.js
const express = require('express');
const request = require('request-promise');
const todoController = require('./todoController');
jest.mock('./todoController');
const app = express();
app.get('/todo', todoController)
test('If certain routes are calling the correct controller , controller should to have been called times one.', async() => {
await request({url: 'http://127.0.0.1/todo'})
expect(todoController).toHaveBeenCalledTimes(1);
})
Actually if you search, there are many references out there.
In the following, I share a few ways that I know.
One of the big conceptual leaps to testing Express applications with mocked request/response is understanding how to mock a chained
API eg. res.status(200).json({ foo: 'bar' }).
First you can make some kind of interceptor, this is achieved by returning the res instance from each of its methods:
// util/interceptor.js
module.exports = {
mockRequest: () => {
const req = {}
req.body = jest.fn().mockReturnValue(req)
req.params = jest.fn().mockReturnValue(req)
return req
},
mockResponse: () => {
const res = {}
res.send = jest.fn().mockReturnValue(res)
res.status = jest.fn().mockReturnValue(res)
res.json = jest.fn().mockReturnValue(res)
return res
},
// mockNext: () => jest.fn()
}
The Express user-land API is based around middleware. AN middleware that takes a request (usually called req), a response (usually called res ) and a next (call next middleware) as parameters.
And then you have controller like this :
// todoController.js
function todoController (req, res) {
if (!req.params.id) {
return res.status(404).json({ message: 'Not Found' });
}
res.send('Hello i am todo controller')
}
They are consumed by being “mounted” on an Express application (app) instance (in app.js):
// app.js
const express = require('express');
const app = express();
const todoController = require('./todoController');
app.get('/todo', todoController);
Using the mockRequest and mockResponse we’ve defined before, then we’ll asume that res.send() is called with the right payload ({ data }).
So on your test file :
// todo.spec.js
const { mockRequest, mockResponse } = require('util/interceptor')
const controller = require('todoController.js')
describe("Check method \'todoController\' ", () => {
test('should 200 and return correct value', async () => {
let req = mockRequest();
req.params.id = 1;
const res = mockResponse();
await controller.todoController(req, res);
expect(res.send).toHaveBeenCalledTimes(1)
expect(res.send.mock.calls.length).toBe(1);
expect(res.send).toHaveBeenCalledWith('Hello i am todo controller');
});
test('should 404 and return correct value', async () => {
let req = mockRequest();
req.params.id = null;
const res = mockResponse();
await controller.todoController(req, res);
expect(res.status).toHaveBeenCalledWith(404);
expect(res.json).toHaveBeenCalledWith({ message: 'Not Found' });
});
});
This is only 1 approach to testing Express handlers and middleware. The alternative is to fire up the Express server.

External API Calls With Express, Node.JS and Require Module

I have a route as followed:
var express = require('express');
var router = express.Router();
var request = require('request');
router.get('/', function(req, res, next) {
request({
uri: 'http://www.giantbomb.com/api/search',
qs: {
api_key: '123456',
query: 'World of Warcraft: Legion'
},
function(error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body)
}
}
});
});
module.exports = router;
I'm trying to make an API call to the Giant Bomb API to bring back whatever data it has about World of Warcraft.
The problem is, the route just loads; it doesn't do anything or it doesn't time out, it's just continuous loading.
I don't know what I'm doing wrong, but that being said... I don't know what's right either. I'm trying to learn as I go along.
Any help would be great.
Thanks
You need to take the data you get from request() and send it back as the response to the original web server request. It was just continuously loading because you never sent any sort of response to the original request, thus the browser was just sitting there waiting for a response to come back and eventually, it will time out.
Since request() supports streams, you can send back the data as the response very simply using .pipe() like this.
var express = require('express');
var router = express.Router();
var request = require('request');
router.get('/', function(req, res, next) {
request({
uri: 'http://www.giantbomb.com/api/search',
qs: {
api_key: '123456',
query: 'World of Warcraft: Legion'
}
}).pipe(res);
});
module.exports = router;
This will .pipe() the request() result into the res object and it will become the response to the original http request.
Related answer here: How to proxy request back as response
Edit in 2021. The request() library has now been deprecated and is no longer recommended for new code. There are many alternatives to choose from. My favorite is the got() library. The above could be accomplished using it like this. This also upgrades to use the pipeline() function which is a better version of .pipe() with more complete error handling.
const router = require('express').Router();
const got = require('got');
const { pipeline } = require('stream');
router.get('/', function(req, res) {
const dataStream = got.stream({
uri: 'http://www.giantbomb.com/api/search',
qs: {
api_key: '123456',
query: 'World of Warcraft: Legion'
}
});
pipeline(dataStream, res, (err) => {
if (err) {
console.log(err);
res.sendStatus(500);
}
});
});
module.exports = router;
For Laravel users,
First of all install npm i axios package if not.
var axios = require('axios');
var config = {
/* Your settings here like Accept / Headers etc. */
}
axios.get('http://local.dev/api/v1/users', config)
.then(function(response) {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
});
Hopefully it will help someone!
Per every route in Express, it is necessary to send a response (partial or complete) or call next, or do both. Your route handler does neither. Try
var express = require('express');
var router = express.Router();
var request = require('request');
router.get('/', function(req, res, next) {
request({
uri: 'http://www.giantbomb.com/api/search',
qs: {
api_key: '123456',
query: 'World of Warcraft: Legion'
},
function(error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body);
res.json(body);
} else {
res.json(error);
}
}
});
});
module.exports = router;
and see what data this route handler responds with.
In 2022
In node
const fetch = (...args) => import('node-fetch')
.then(({default: fetch}) => fetch(...args));
app.get('/checkDobleAPI', async (req, res) => {
try {
const apiResponse = await fetch(
'https://jsonplaceholder.typicode.com/posts')
const apiResponseJson = await apiResponse.json()
console.log(apiResponseJson)
res.send('Running 🏃')
} catch (err) {
console.log(err)
res.status(500).send('Something went wrong')
}
})

Categories