ERR_ABORTED 431 (Request Header Fields Too Large) - node.js

Have started using a proxy for my react app/express server. Currently I am trying to run a simple fetch operation but getting this response:
GET http://localhost:3000/api/recipes net::ERR_ABORTED 431 (Request Header Fields Too Large)
I have tried adjusting the allowable size of headers in my package.json I have cleared cache, the header I am sending seems reasonably small. So really scratching my head on this one.
Here is my code:
RecipeList.jsx
export default function RecipeList() {
const [recipeList, setRecipeList] = useState([])
const retrieveAllRecipes = function () {
fetch('/api/recipes', {
method: 'GET',
})
.then((response) => {
console.log(response)
})
.catch((err) => {
console.log('Error Reading data ' + err)
})
}
routes.js
const express = require('express')
const db = require('./db')
const router = express.Router()
router.get('/api/recipes', (req, res) => {
db.readRecipes()
.then((result) => {
console.log(result)
})
.catch((err) => {
logError(err)
})
})
function logError(err) {
console.error('Uh oh!', err.message)
}
module.exports = {}
db.js
const config = require('./knexfile').development
const connection = require('knex')(config)
function readRecipes(db = connection) {
return db('recipes').select()
}
module.exports = {
readRecipes,
}
I am using node v16x and have altered my package.json for my proxy:
"proxy": "http://localhost:3001",

Related

React pass params with Axios post

I want to pass a params to server using Axios.post but it didn't work with 404 error any ideas??
code:
function Movie() {
const { index } = useParams(); // get index from path /movie/:index
const [movie, setMovie] = useState([]);
useEffect(() => {
Axios.post("http://localhost:3001/movie", {
params: { id: index },
})
.then((response) => {
setMovie(response.data);
})
.catch((err) => {
console.log(err);
});
}, []);
return (
<body>
abc
{index}
{movie.id}
</body>
);
}
Server:
app.post('/movie', async (req, res)=>{
let id= req.params.id;
let movie=[];
movie.push(id);
res.send(movie);
});
A 404 Error means that the path /movie cannot be found on the API. Perhaps ensure that the route on your server is named correctly.

How do I debug server-side errors on MERN?

I have this front-end code:
export const CreatePage = () => {
const auth = useContext(AuthContext)
const {request} = useHttp()
const [content, setContent] = useState('')
const [title, setTitle] = useState('')
const [lead, setLead] = useState('')
useEffect(() => {
window.M.updateTextFields()
},[])
const postHandler = async () => {
try {
const data = await request('/api/post/generate', 'POST', {title: title, lead: lead, content: content}, {
Authorization: `Bearer ${auth.token}`
})
console.log(data)
} catch (e) {}
}
And this back-end code:
router.post('/generate', auth, async (req, res) => {
try {
const baseURL = config.get('baseURL')
const {title, lead, content} = req.body
// if (!title || !lead || !content) {
// return res.status(422).json({error: 'Please, input ALL fields'})
// }
const Post = new Post({
title, lead, content, owner: req.body.user.userId // req.user.userId
})
await Post.save()
res.status(201).json({Post})
} catch (e) {
res.status(500).json({message: 'Something went wrong'})
}})
I've tried a lot of things, but I still get this error. I know this is a server-side error, but that's all I have been able to figure out.
P.S. If there are any questions about the code, I will add it later.
UPD: By the way, could it be a problem's reason? Console log:
[1] Proxy error: Could not proxy request /api/post/generate from localhost:3000 to http://localhost:5000.
Probably, it's because of cors, you just can't send request from different url's. Try to install cors and configure it:
const cors = require("cors");
app.use("/", require('./src/routes'));
app.use(cors({
origin: '*'
}))

How to mock multer using jest/enzyme to file upload using axios post mock call

I am testing my express router with axios post-call to backend. I am getting 500 responses instead of 200, not sure how to mock the multer effectively.
Any thoughts on this? Thanks
routes.jsx
const axios = require('axios')
const router = express.Router()
const multer = require('multer')
const FormData = require('form-data')
const express = require('express')
const upload = multer({ storage: multer.memoryStorage() }).any()
router.post('/', upload, (req, res) => {
const formData = new FormData()
const { body } = req
req.files.forEach(file => {
formData.append(
'files',
file.buffer,
{
filename: file.originalname
},
file.originalname
)
})
axios
.post('/api/endpoint', formData)
.then(response => {return response
})
.catch(e => {
console.log(e)
})
})
module.exports = router
Below are my test case
routes.jsx.test
const axios = require('axios')
const MockAdapter = require('axios-mock-adapter')
const myroute = require('myroute')
const app = express()
const mock = new MockAdapter(axios)
const request = require('supertest')
const express = require('express')
const bodyParser = require('body-parser')
const multer = require('multer')
jest.mock('multer')
multer.mockImplementation(() => {
return {
any () {
return (req, res, next) => {
req.body = { userName: 'testUser' }
req.files = [
{
originalname: 'sample.name',
mimetype: 'sample.type',
path: 'sample.url'
}
]
return next()
}
}
}
})
app.use(bodyParser.json())
app.use('/', myroute)
describe('sendFiles', () => {
const url = '/api/endpoint'
test('200 response', () => {
const myMockRes = { mykey: 'myVal' }
let formData = new FormData()
const file = new Blob(['somee contents'], { type: 'multipart/form-data' })
formData.append('files', file)
formData.append('userName', 'testUser')
mock.onPost(url).reply(200, myMockRes)
return (
request(app)
.post('/')
.send({ userName: 'testUser', files: [file] })
//.expect('Content-Type', /json/)
.expect(200)
.then(response => {
const { data } = response.body
expect(data).toEqual(myMockRes)
})
)
})
})
error:
TypeError: Cannot read property 'any' of undefined in routes.jsx
const upload = multer({ storage: multer.memoryStorage() }).any()
When you use jest.mock('multer'), Jest automatically mocks the module and returns undefined when it gets called in the test. Since we want to mock memoryStorage and any methods as well, we have to do it explicitly by passing a factory as the second argument to jest.mock.
jest.mock('multer', () => {
const multer = () => ({
any: () => {
return (req, res, next) => {
req.body = { userName: 'testUser' }
req.files = [
{
originalname: 'sample.name',
mimetype: 'sample.type',
path: 'sample.url',
buffer: Buffer.from('whatever'), // this is required since `formData` needs access to the buffer
},
]
return next()
}
},
})
multer.memoryStorage = () => jest.fn()
return multer
})
The other issue is that Blob does not exist in Node. You can use Buffer.from to generate a buffer to send in the request.
const file = Buffer.from('whatever')
And you don't need to use FormData in the test.
The whole code:
// router.test.js
const axios = require('axios')
const MockAdapter = require('axios-mock-adapter')
const express = require('express')
const app = express()
const mock = new MockAdapter(axios)
const request = require('supertest')
const bodyParser = require('body-parser')
const myroute = require('./router')
jest.mock('multer', () => {
const multer = () => ({
any: () => {
return (req, res, next) => {
req.body = { userName: 'testUser' }
req.files = [
{
originalname: 'sample.name',
mimetype: 'sample.type',
path: 'sample.url',
buffer: Buffer.from('whatever'),
},
]
return next()
}
},
})
multer.memoryStorage = () => jest.fn()
return multer
})
app.use(bodyParser.json())
app.use('/', myroute)
describe('sendFiles', () => {
const url = '/api/endpoint'
test('200 response', () => {
const myMockRes = { mykey: 'myVal' }
const file = Buffer.from('whatever')
mock.onPost(url).reply(200, myMockRes)
return request(app)
.post('/')
.send({ userName: 'testUser', files: [file] })
.expect(200)
.then((response) => {
const { data } = response.body
expect(data).toEqual(myMockRes)
})
})
})
#Arun Kumar Mohan got me halfway there. Good happy path. But what about the error path? Arun has it right. You need to mock this. But what about triggering error paths within the callback? Providing a jest function that you can trigger can get you into those error paths.
import { UploadGuard } from '../../../src/guards';
import { Request } from 'express';
// Note: make a spy to get into the guts of the thing.
let spy = jest.fn();
jest.mock('multer', () => {
const multer = () => ({
any: () => {
return (req, res, next) => {
// Note: have the spy execute in the next.
return next(spy());
};
},
});
multer.memoryStorage = () => jest.fn();
return multer;
});
describe('Upload Guard', () => {
let guard: UploadGuard;
const loggerService = new MockLogger();
// Note: Good practice, always reset your mocks.
afterEach(() => jest.resetAllMocks());
beforeEach(() => {
spy = jest.fn();
guard = new UploadGuard(loggerService);
});
it('Should set the files on a request', async () => {
// Given
const executionContext = {
switchToHttp: () => ({
getRequest: () =>
({
headers: {
authorization: 'Bearer FakeJWT',
Content-Type: 'multipart/form-data',
},
body: {},
} as Request),
}),
};
// When
await guard.canActivate(executionContext as any);
// Then
expect(spy).toHaveBeenCalled();
});
it('Throw an error if something bad happens', async () => {
// Given
spy.mockImplementationOnce(() => {
// Note: Return not throw
return new Error('Bad Things');
});
const executionContext = {
switchToHttp: () => ({
getRequest: () => ({} as Request),
}),
};
try {
// When
await guard.canActivate(executionContext as any);
throw new Error('Should not happen');
} catch (err) {
// Then
expect(err.message).toBe('Bad Things');
}
});
});

why is axios fetch not working on mobile?

I have the following setup which works on my PC but doesn't on mobile even when there is data to fetch.
useEffect(() => {
const {username, room} = queryString.parse(location.search);
setRoom(room);
if (messages.length > 3) {
let lastMessage = messages.pop();
setMessss([lastMessage]);
const fetchHistory = async () => {
try {
const result = await axios.get(`https://example.com/messages/${room}`,);
setMessss(result.data.messagesFromAPI);
} catch (error) {
console.log(error);
}
};
fetchHistory();
}
}, [messages]);
I also have another useEffect hook that works on PC on componentDidMount but doesn't work if I reload the page more than once but I want it to work on every page reload but it doesn't fetch...
could this be because I use the free subscription (M0) on Mongodb Atlas? Although from metrics my database hasn't exhausted or reached capacity.
useEffect(() => {
const {username, room} = queryString.parse(location.search);
// setRoom(room);
axios.get(`https://example.com/messages/${room}`)
.then(response => {
const history = response.data.messagesFromAPI;
setMessss(history);
})
.catch(error => {
console.log(error.response);
});
},[]);
Here's how I solved it
In the src folder just add a file called
setupProxy.js
and write this code inside
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
["/api/*",], // the base api route you can change it
createProxyMiddleware({
target: "http://localhost:4000", // the local server endpoint
})
);
};
make sure to change the target port to the port where the server is running.
For some reason axios does not behave properly locally.
You can add the setupProxy.js to .gitignore

Send response from server side axios request to React/Redux app

I'm a little new to creating a backend in Node/Express, but I am trying use axios to make HTTP requests. I've set up express routes that will make the necessary request and I know from using Postman that GET request I'm testing does return a response. Where I'm stuck is how to return that data and send it to my React/Redux app to use.
-Server Side-
//Express Route
app.get('/api/recipes', recipeController.getRecipes)
//Controller Function that makes axios request
const axios = require('axios')
const Promise = require('bluebird')
module.exports = {
getRecipes(req, res) {
const url = "https://gw.hellofresh.com/api/recipes/search?country=us&limit=9"
const token = "IUzI1NiIsInR5c"
axios
.get(url, {
"headers": {"Authorization": "Bearer " + token}
})
.then((response) => {
console.log(response)
})
.catch((err) => {
console.log(err)
})
}
}
-Client Side-
I dispatch the following action and make a call using the endpoint I created. However, at this point, I'd get an error status even though on the server side I was able to get a response. I tried playing around using Promises as I read that axios GET requests returns promises, but couldn't wrap my head around on how to implement it.
export const getRecipes = () => {
return (dispatch) => {
axios
.get('/api/recipes')
.then((resp) => {
console.log(resp)
})
.catch((err) => {
console.log(err)
})
}
}
You need to call res.send in the route, to send the data to the client:
module.exports = {
getRecipes(req, res) {
const url = "https://gw.hellofresh.com/api/recipes/search?country=us&limit=9"
const token = "IUzI1NiIsInR5c"
axios
.get(url, {
"headers": {"Authorization": "Bearer " + token}
})
.then(response => {
console.log(response)
res.send(response) // <= send data to the client
})
.catch(err => {
console.log(err)
res.send({ err }) // <= send error
})
}
}

Resources