Error: Cannot get orders: TypeError: Cannot read properties of undefined (reading 'connect') - node.js

I'm trying to build an API with express and pg. Whenever I try to access an endpoint that is related to a query to the database I get the error above.
My handler function is as follows:
import { Request, Response, Router, NextFunction } from 'express';
import { Orders } from '../models/order';
const orders = new Orders;
const index = async (_req: Request, res: Response, next: NextFunction) => {
try {
const ordersList = await orders.index();
res.json(ordersList);
} catch (err) {
next(err)
}
}
const ordersRoute = Router();
ordersRoute.get('/', index);
This handler refers to the following model:
import { Pool } from 'pg';
client = new Pool({
host: POSTGRES_HOST,
database: POSTGRES_DB,
user: POSTGRES_USER,
password: POSTGRES_PASSWORD,
port: parseInt(POSTGRES_PORT as string, 10)
export class Orders {
async index(): Promise<Order[]> {
try {
const conn = await client.connect();
const sql = 'SELECT * FROM orders';
const result = await conn.query(sql);
conn.release();
return result.rows;
} catch (err) {
throw new Error(`Cannot get orders: ${err}`);
}
}
}
anytime I try to access the endpoint I get
Error: Cannot get orders: TypeError: Cannot read properties of
undefined (reading 'connect')
in the console.
any idea how to fix ?

So how things work in your case.
All modules are read by nodejs starting from your index one by one from top to bottom.
In your script, you declare client and then export a class. In that case, your client is setup, then you export a class, and that file is completed, meaning that the only thing that remains is the exported thing. So when you try to use the exported class, you'll not have the same context as in your module.
You need to export the client too and import it where you need that class or to include client definition inside the class

Related

how to prevent file upload when body validation fails in nestjs

I have the multipart form to be validated before file upload in nestjs application. the thing is that I don't want the file to be uploaded if validation of body fails.
here is how I wrote the code for.
// User controller method for create user with upload image
#Post()
#UseInterceptors(FileInterceptor('image'))
create(
#Body() userInput: CreateUserDto,
#UploadedFile(
new ParseFilePipe({
validators: [
// some validator here
]
})
) image: Express.Multer.File,
) {
return this.userService.create({ ...userInput, image: image.path });
}
Tried so many ways to turn around this issue, but didn't reach to any solution
Interceptors run before pipes do, so there's no way to make the saving of the file not happen unless you manage that yourself in your service. However, another option could be a custom exception filter that unlinks the file on error so that you don't have to worry about it post-upload
This is how I created the whole filter
import { isArray } from 'lodash';
import {
ExceptionFilter,
Catch,
ArgumentsHost,
BadRequestException,
} from '#nestjs/common';
import { Request, Response } from 'express';
import * as fs from 'fs';
#Catch(BadRequestException)
export class DeleteFileOnErrorFilter implements ExceptionFilter {
catch(exception: BadRequestException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
const getFiles = (files: Express.Multer.File[] | unknown | undefined) => {
if (!files) return [];
if (isArray(files)) return files;
return Object.values(files);
};
const filePaths = getFiles(request.files);
for (const file of filePaths) {
fs.unlink(file.path, (err) => {
if (err) {
console.error(err);
return err;
}
});
}
response.status(status).json(exception.getResponse());
}
}

Error: addReview is not a function in MERN application

I'm following along with a tutorial to create a movie review app on the MERN stack.
When calling my API using Insomnia, I'm getting the error "ReviewsDAO.addReview is not a function"
reviewsDAO.js:
import mongodb from "mongodb"
const ObjectId = mongodb.ObjectId
let reviews
export default class ReviewsDAO{
static async injectDB(conn){
if(reviews){
return
}
try { reviews = await conn.db(process.env.MOVIEREVIEWS_NS).collection('reviews')}
catch(e){
console.error(`unable to establish connection handle in reviewDAO: ${e}`)
}
}
static async addReview(movieId, user, review, date){
try{
const reviewDoc = {
name: user.name,
user_id: user._id,
date: date,
review: review,
movie_id: ObjectId(movieId)
}
return await reviews.insertOne(reviewDoc)
}
catch(e) {
console.error(`unable to post review ${e}`)
return {error: e}
}
}
reviews.controller.js:
import ReviewsDAO from '../dao/reviewsDAO.js'
export default class ReviewsController{
static async apiPostReview(req,res,next) {
const reviewsDAO = new ReviewsDAO()
try{
const movieId = req.body.movie_id
const review = req.body.review
const userInfo = {
name: req.body.name,
_id: req.body.user_id
}
const date = new Date()
const ReviewResponse = await reviewsDAO.addReview(
movieId,
userInfo,
review,
date
)
res.json({status: "success"})
}
catch(e) {
res.status(500).json({error: e.message})
}
}
The reviews collection is also not being created in MongoDB. But maybe that isn't supposed to happen until we create our first review.
Why isn't my function being called appropriately?
You need to instantiate a ReviewsDAO object in order to call its methods.
const reviewsDAO = new ReviewsDAO()
Then you will be able to access the addReview() method
You are calling the class method without initializing the object.
For example:
class Animal{
function sayhello(){
console.log("Hello")
}
}
// I can call the sayhello method by creating an object.
var dog=new Animal()
dog.sayhello() //prints "Hello"
But in your case, you are calling the method without creating the object.
Animal.sayhello()
// It will create an error
So initialise the object and call the method
const reviewsDAO = new ReviewsDAO()
reviewDAO.addreviews()
The static keyword defines static methods for classes.
Static methods are called directly on the class (Car from the example above) - without creating an instance/object (mycar) of the class
So
const Reviewsdao= new ReviewsDAO()
ReviewsDAO().addreviews()
Call the method with the class name after initialising it.

TypeORM and MongoDB and Repositories: Cannot read property 'prototype' of undefined

I'm trying implement TypeORM with MongoDB using repositories. However, when I try to make use of repositories to manage the database, using the same structure as in this repository, things go a bit sideways. I'm getting the following error:
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'prototype' of undefined
I have tried the following code:
import { Request, Response } from 'express';
import { getMongoRepository } from "typeorm";
import Task from "../models/Task";
export default class TasksController {
async listAll(request: Request, response: Response): Promise<Response> {
const tasksRepository = getMongoRepository(Task);
try {
const tasks = await tasksRepository.find();
return response.status(200).json({ "items": tasks });
} catch (err) {
return response.status(400).json({
message: err.message,
});
}
}
}
I know the error refers to implementing the .find() method. I have even managed to fetch the data, using a suggestion from this post replacing:
const tasks = await tasksRepository.find();
with
const tasks = await tasksRepository.createCursor(tasksRepository.find()).toArray();
but I still get the above mentioned error.
Anyone understands what's going on?
I have also managed to save data directly to the database through the use of the following script:
server.ts
import express from 'express';
import { createConnection } from 'typeorm'
const app = express();
const port = 3333;
createConnection();
app.use(express.json());
app.post('/tasks', (async (request, response) => {
const { item } = request.body;
task.item = item;
const task = new Task();
(await connection).mongoManager.save(task);
return response.send(task);
}))
app.listen(port, () =>
console.log(`Server running on port ${port}`)
);
TypeORM is not support mongodb v4.
https://github.com/nestjs/nest/issues/7798
You can use 3.7.0 instead.
I submitted a pull requests to resolve this. https://github.com/typeorm/typeorm/pull/8412 if anyone is looking for a workaround in the meantime.

Next.js not build when using getStaticPaths and props

I'm trying to run next build when using getStaticProps and getStaticPaths method in one of my routes, but it fails every time. Firstly, it just couldn't connect to my API (which is obvious, they're created using Next.js' API routes which are not available when not running a Next.js app). I thought that maybe running a development server in the background would help. It did, but generated another problems, like these:
Error: Cannot find module for page: /reader/[id]
Error: Cannot find module for page: /
> Build error occurred
Error: Export encountered errors on following paths:
/
/reader/1
Dunno why. Here's the code of /reader/[id]:
const Reader = ({ reader }) => {
const router = useRouter();
return (
<Layout>
<pre>{JSON.stringify(reader, null, 2)}</pre>
</Layout>
);
};
export async function getStaticPaths() {
const response = await fetch("http://localhost:3000/api/readers");
const result: IReader[] = await response.json();
const paths = result.map((result) => ({
params: { id: result.id.toString() },
}));
return {
paths,
fallback: false,
};
}
export async function getStaticProps({ params }) {
const res = await fetch("http://localhost:3000/api/readers/" + params.id);
const result = await res.json();
return { props: { reader: result } };
}
export default Reader;
Nothing special. Code I literally rewritten from the docs and adapted for my site.
And here's the /api/readers/[id] handler.
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const knex = getKnex();
const { id } = req.query;
switch (req.method) {
case "GET":
try {
const reader = await knex
.select("*")
.from("readers")
.where("id", id)
.first();
res.status(200).json(reader);
} catch {
res.status(500).end();
}
break;
}
}
Nothing special either. So why is it crashing every time I try to build my app? Thanks for any help in advance.
You should not fetch an internal API route from getStaticProps — instead, you can write the fetch code present in API route directly in getStaticProps.
https://nextjs.org/docs/basic-features/data-fetching#write-server-side-code-directly

How to use connection as standalone object with types?

Not working code just to illustrate what I'm trying to achieve
Some connection file
import { ConnectionManager } from 'typeorm';
const c = new ConnectionManager();
// user ormconfig.conf file
export const connection = c.createAndConnect();
using in some model
#Entity()
#Table("annual_incomes")
export class AnnualIncome
{
#PrimaryGeneratedColumn()
id: number;
#Column({ length: 75 })
variant: string;
#Column("int")
sort: number;
#Column()
is_active: boolean;
}
Later somewhere in the code, I want to get connection with all methods, something like:
import { connection } from 'someconnection';
import { AnnualIncome } from 'entities';
// some code here
api.get('/incomes', async(ctx) => {
ctx.body = await connection.getRepository(AnnualIncome).find();
});
Usually, I'm getting an error from tsc that .getRepository() method was not found in connection. However if I do something like:
import { connection } from 'someconnection';
import { AnnualIncome } from 'entities';
// some code here
api.get('/incomes', async(ctx) => {
ctx.body = await connection.then(async connection => {
return await connection.getRepository(AnnualIncome).find();
}
});
the above code works with definitions and tsc does not complain about not-existing methods.
I'd like to avoid an extra definition connection.then() and get plain connection with all methods defined in <Connection> type.
just use createConnection method to create your connection when you bootstrap your application. Later you can access your connection from anywhere using getConnection() method:
import { AnnualIncome } from 'entities';
import { createConnection, getConnection } from 'typeorm';
// somewhere in your app, better where you bootstrap express and other things
createConnection(); // read config from ormconfig.json or pass them here
// some code here
api.get('/incomes', async(ctx) => {
ctx.body = await getConnection().getRepository(AnnualIncome).find();
});
Also you can simply use getRepository method also avalible from anywhere:
import { AnnualIncome } from 'entities';
import { getRepository } from 'typeorm';
// some code here
api.get('/incomes', async (ctx) => {
ctx.body = await getRepository(AnnualIncome).find();
});

Resources