NestJS/ExpressJs too many parameters - node.js

I am trying to send a file to a NestJS controller but keep getting a too many parameters exception. I have installed bodyParser and updated the request size limit to get around a request too large exception.
main.ts:
import { NestFactory } from "#nestjs/core";
import { ApplicationModule } from "./app/app.module";
import * as express from "express";
import * as bodyParser from "body-parser";
async function bootstrap() {
const server = express();
server.use(bodyParser({limit: '50mb'}));
console.log(server);
const app = await NestFactory.create(ApplicationModule, server);
await app.listen(process.env.PORT || 3000);
}
bootstrap();
Controller:
import { Get, Controller, Query, Post, Request } from "#nestjs/common";
import { CloudVisionLogoService } from "./logos.component";
#Controller("logos")
export class LogoRecognitionController {
public constructor(
private readonly _logoRecognition: CloudVisionLogoService
) {
}
#Post()
public async detectLogos(#Request() req) {
console.log(req.files[0]);
// return await this._logoRecognition.detectLogos(imageUri);
}
}
Postman request (not shown, binary attachment of image):
POST /logos HTTP/1.1
Host: localhost:3000
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Postman-Token: c95da069-c602-58a9-1e05-36456a527f02
undefined

The following is from body-parser docs:
This does not handle multipart bodies, due to their complex and
typically large nature. For multipart bodies, you may be interested in
the following modules:
busboy and connect-busboy
multiparty and connect-multiparty
formidable
multer
I suggest you to use multer package because it's easy and many users use it

Related

How to get req.body data using TypeScript, Express and Node with Routes in different files

I have been trying to answer this for days, searched through stackoverflow, the web and even rebuilt this multiple times.
I am trying to setup an express app using TypeScript to create a RESTApi, and I would like to keep my routes and controllers in separate files so I can have it organized.
I am open to other suggestions if this isn't the be best way.
The problem I am having is that if I output req.body it spits out the JSON that was sent but if I try to access req.body['order_key'] or req.body.order_key we get undefined
What am I doing wrong? :)
index.ts
import * as functions from 'firebase-functions';
import express from 'express';
// import * as bodyParser from 'body-parser';
import orderRoutes from './routes/orderRoutes';
// import {getAllOrders, updateOrder} from './orderController';
const app = express();
app.use(express.json());
// app.use(bodyParser.json()); // tried
// app.use(bodyParser.urlencoded({ extended: true })); // tried
app.use(express.urlencoded({extended: true}));
app.use('/orders', orderRoutes);
app.get('/', (req, res) => res.status(200).send('Hey there!'));
// handle orders
// app.get('/orders', getAllOrders);
// app.post('/orders', updateOrder);
exports.app = functions.https.onRequest(app);
I have tried to use bodyParser, the built in parser, all parser to get this to work
orderRoutes.ts
import {Router} from 'express';
import {getAllOrders, updateOrder} from '../controllers/orderController';
// eslint-disable-next-line new-cap
const router = Router();
router.route('/').post(updateOrder);
router.route('/').get(getAllOrders);
export default router;
orderController.ts
import {Request, Response} from 'express';
const getAllOrders = (req: Request, res: Response) => {
res.status(200).send({
status: 'success',
message: 'Welcome',
});
};
const updateOrder = async (req: Request, res: Response) => {
res.status(200).send({
status: 'success',
message: 'Order created',
data: 'data ' + req.body['order_key'] + req.body.order_key, // THIS IS THE ISSUE COMES UP UNDEFINED
});
};
export {getAllOrders, updateOrder};
All the other routes work, here is the payload I am sending:
[
{
"id": 26442,
"parent_id": 0,
"customer_id": 1489,
"order_key": "wc_order_DQSfOIyzobd4k"
}
]
Using postman and I have it to RAW and with JSON on, screenshots below
Post issue
Post issue
Headers
Headers
Any help appreciated
Well, your payload is an array with one object in it. As you show:
[
{
"id": 26442,
"parent_id": 0,
"customer_id": 1489,
"order_key": "wc_order_DQSfOIyzobd4k"
}
]
The brackets at the beginning and end indicate an array. If you really intend for the payload to be an array, then you would need to use req.body[0] to access the first object in that array.
Or, req.body[0].order_key to get the key.
Or, if you want to process more than one object (if there is more than one in the array), then you would use a for loop to loop over the objects in the array.
Or, if the API is really just supposed to be sent one object, then fix the client-side so you're sending the JSON version of just a single object:
{
"id": 26442,
"parent_id": 0,
"customer_id": 1489,
"order_key": "wc_order_DQSfOIyzobd4k"
}

How do i fill my parameter req.body with axios (Vue.js) to my Express.js server

Im trying to send a connect call to my api from my vue (i use vue.js),
but when i get the object req.body in my back, the object is empty
I've read this : Axios post request.body is empty object
but it didn't help me
(it works from Postman with the body filled and the option x-www-form-encoded)
i got this got from my Vue :
My vue service.js
import Axios from 'axios';
class APIClient {
constructor () {
this.client = Axios.create({
baseURL: 'http://localhost:8080'
});
}
async connect () {
const params = new URLSearchParams();
params.append('mail', 'test');
params.append('pwd', 'mypwd');
return await this.client.get('/api/user/auth', params);
}
and i got this in my back :
index.ts :
import express from "express";
var cors = require('cors');
import "reflect-metadata";
var bodyParser = require('body-parser')
const http = require('http');
const MainRouter = require('./routes/main_router');
let port = 8080;
const server = express();
server.use(cors({origin: true}))
server.use(bodyParser.json());
server.use(bodyParser.urlencoded({extended: true}))
let mainRouter = new MainRouter(server);
const httpServer = http.createServer(server);
httpServer.listen(port);
console.log('Server is listening');
and the main_router.ts
import express from 'express';
import mysql from "promise-mysql";
export default class MainRouter {
public server: express.Express;
constructor (server: express.Express) {
super();
this.server = server;
this.server.get("/api/user/auth", async (req: any, res: any) => {
if (req.body) //the req.body is equal to {} instead of {mail: 'test', ...
return res.json(await this.userManager.getUserByCredidentials(req.body));
else return res.json([])
});
}
}
module.exports = MainRouter;
I don't know if i have something to add in my express server or in my vue with axios ?
You are passing the mail and pwd as GET parameters and not at the request body. You can access the using req.query, but ....
You should avoid sending creds as parameters of the url with GET, use the body and POST instead. For more information see this post.
Here is an example:
return await this.client.post('/api/user/auth', {
mail: "test",
pwd: "mypwd"
});
and of course do not forget to change this.server.get("/api/user/auth",... to this.server.post("/api/user/auth",...

Nodejs express routes in different files Express object automatically turns into a Router object

I have a Nodejs with express application. I register my routes using tsoa.
When i add swagger-ui-express to my nodejs application I get the following error Error: TypeError: Router.use() requires a middleware function but got a undefined
I initialize the app as follows:
app.ts
import config from './api/build/config';
import express from 'express';
function startServer() {
const app = express();
require('./api/loaders').default(app);
app.listen(config.port, () => {
console.log(`
################################################
🛡️ Server listening on port: ${config.port} 🛡️
################################################
`);
});
}
startServer();
loaders\index.ts
import {Express} from 'express';
export default (app: Express) => {
require('./express').default(app);
console.log('✌️ Express loaded');
require('./swagger').default(app);
console.log('✌️ Swagger loaded');
};
express.ts
import bodyParser from 'body-parser';
import {Express, Request, Response, NextFunction} from 'express';
import logger from 'morgan';
import { RegisterRoutes } from '../routes';
import cors from 'cors';
export default function startExpress(app: Express) {
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(cors());
//register all routes from the routes generated by tsoa
RegisterRoutes(app);
// catch 404 and forward to error handler
app.use((request: Request, response: Response, next: NextFunction) => {
const error = new Error('404 Not Found');
error['status'] = 404;
next(error);
});
// error handlers
// error handler will print stacktrace only in development
app.use((error: any, request: Request, response: Response) => {
response.locals.message = error.message;
response.locals.error = request.app.get('env') === 'development' ? error : {};
response.status(error.status || 500);
response.send(error.message);
});
}
swagger.ts
import { Express } from 'express';
import swaggerUi from 'swagger-ui-express';
export default function startSwagger(app: Express) {
try{
const swaggerDocument = require('../build/swagger.json');
var options = {
explorer: true
};
app.use('/swagger', swaggerUi.server, swaggerUi.setup(swaggerDocument, options));
}
catch(error){
throw new Error(error);
}
}
I also tried to use import statements instead of require, but it doesn't make a difference. Why does my compiler suddenly say my app Express object is a Router object and how do I set up nodejs with express and registering routes in different files?
To answer your question...
Why does my compiler suddenly say my app Express object is a Router object...
It doesn't. You can see a reference to the Router.use() function because it is just eventually called inside the app.use() function.
The actual issue here as mentioned in the error message is the middleware function being undefined. This is because inside your swagger.ts file, you specified swaggerUi.server as the middleware function but it needs to be changed to swaggerUi.serve.
import { Express } from 'express';
import swaggerUi from 'swagger-ui-express';
export default function startSwagger(app: Express) {
try{
const swaggerDocument = require('../build/swagger.json');
var options = {
explorer: true
};
// The problem was here... change server to serve
app.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerDocument, options));
}
catch(error){
throw new Error(error);
}
}

Organizing express.Router with a class?

I'm experimenting with organizing my routes with Express router and classes in Typescript. This is what I've tried so far. The index.ts file is supposed to reference the Notes class in the notes.ts file which exposes an endpoint via a private method.
So, for example, I have a file index.ts
import * as express from "express";
import rootRoutes from "./root";
import { Notes } from "./notes";
import accountRoutes from "./account";
const router: express.Router = express.Router();
router.use("/", rootRoutes);
router.use("/account", accountRoutes);
router.use("/notes", Notes.routes);
export = router;
and another file notes.ts:
import express, { Router, Request, Response, NextFunction } from "express";
const router: express.Router = express.Router();
export class Notes {
constructor() {
this.routes();
}
private routes(): void {
//Get notes
router
.route("/")
.get((req: Request, res: Response, next: NextFunction) => {
res.send("notes");
});
}
}
What am I missing here?
You are calling a private method router.use("/notes", Notes.routes);
To use it like you did, first you have to instantiate the class or make the method static.
Mixing class instance state with router state can be tricky, try to keep it free of any instance state.
Also I would suggest you to simplify that implementation, to something like this:
export class Notes {
static handler(req: Request, res: Response): void {
res.send('Hello from A!')
}
}
app.get('/', Notes.handler);

POST request not returning Allow-Origin header

I'm trying to make a POST request on a AWS lambda that has cors enabled and I using the cors package in the API.
Then I make a POST request with fetch but I get this error:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
The cors package was not supposed to take tare of this or I need to do some additional configuration?
api.js
import { json, urlencoded } from 'body-parser'
import express from 'express'
import cors from 'cors'
import recipe from './routes/recipe'
import login from './routes/login'
import unit from './routes/unit'
const app = express()
app.use(cors()) // enabling cors
app.use(json())
app.use(urlencoded({ extended: true }))
app.use('/recipes', recipe)
app.use('/login', login)
app.use('/units', unit)
request.js
const params = { 'POST', body, mode: 'cors' }
return await (await fetch(baseURL + endpoint, params)).json()
recipe.js
import { Router } from 'express'
const router = Router()
router.post('/', async ({ body }, res) => {
// save recipe in database
res.json(recipeId)
})
export default router
full source code - api: https://github.com/EliasBrothers/zanzas-recipes-api/tree/beta-develop
frontend - https://github.com/EliasBrothers/zanzas-recipes-web/tree/develop
I made it work by updating the packages from the project and changing the request
const stringifiedBody = JSON.stringify(body) // added
const params = {
method,
body: stringifiedBody,
mode: 'cors',
headers: { // added
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}
I'm not sure if this is a copying error, you didn't specify the fetch method POST in right way. Sometimes a Not Found page will also be recognized as CORS problem. Have you tried to normalize your fetch parameters?
params = {
method: 'POST',
body: body,
mode:'cors'
}

Resources