Storing file in PostgreSQL database using NestJS - javascript

I have one form in React. It has many fields. once user click on the submit button all the field should be saved in database. It also contains one file attachment(pdf).
I dont know what the datatype of variable which will store file, I should take in entity class. Also what should be the database column type. I am using TypeORM for the same.
#IsNotEmpty()
#IsDate()
endDate: Date;
#Column()
#IsNotEmpty()
#IsString()
personIncharge: string;
#Column()
#IsNotEmpty()
#IsString()
country: string;
#Column()
#IsNotEmpty()
#IsString()
comments: string;
attachFile: string; // Should I take file or string?

You will probably find your solution in this StackOverflow comment
Basically, you turn your column type in a blob or longblob in your TypeORM annotation, and then use the type Buffer in your Entity's field
#Column({type: 'longblob'})
attachFile: Buffer;
Then you will be able to serve the file as showed in the post example:
app.get("/file/:id", async (req, res)=>{
try {
const repo = getConnection().getRepository(MYFile)
const result_find = await repo.findOne(req.params.id)
console.log(result_find);
var fileData = result_find.data;
res.writeHead(200, {
'Content-Type': result_find.mimeType,
'Content-Disposition': 'attachment; filename=' + result_find.name,
'Content-Length': fileData.length
});
res.write(fileData);
res.end();
} catch (error) {
console.log(error)
res.send("ERROR")
}
})

if you want using string, client must send base64 file to backend.
format: data:(mimetype);(charset),(encoded) -> data:image/png;base64,\ee\9f920d....
here solution, using base64 string
DTO (data transfer object)
import { IsDefined, IsNotEmpty } from 'class-validator';
export class UpdateUserAvatarDto {
#IsDefined()
#IsNotEmpty()
file: string;
}
controller
#UseGuards(JwtAuthGuard)
#Patch('account/avatar')
async updateAvatar(
#User() user: Payload,
#Body() updateUserAvatarDto: UpdateUserAvatarDto,
#Res() res: Response,
) {
try {
const { file } = updateUserAvatarDto;
createFile(file, { prefix: ['user', 'avatar'], name: user.id }); // file is string base64 you can store it to database.
return response(res, HttpStatus.OK, {
message: 'Successfully update avatar',
});
} catch (e) {
console.error(e);
return response(res, HttpStatus.INTERNAL_SERVER_ERROR, {
message: e,
data: null,
});
}
}
if you want to create a file from base64
export const createFile = async (base64, { prefix, name }) => {
const cleanBase64 = base64.split(',')[1];
const buffer = Buffer.from(cleanBase64, 'base64');
const file = await fileType.fromBuffer(buffer);
return fs.writeFileSync(
path.join(
path.resolve('./'),
...['public', ...prefix, `${name}.${file.ext}`],
),
buffer,
);
};

Related

Message (user) attribute 'tracestate' must contain a non-empty value of type 'String'

Getting Message (user) attribute 'tracestate' must contain a non-empty value of type 'String' while trying to push the data in AWS SQS.
Using below body and function to push the data
Function used
import aws, { SQS } from 'aws-sdk';
import { ServiceConfigurationOptions } from 'aws-sdk/lib/service';
export default abstract class AbstractSQSPublisherService {
protected sqs: SQS;
private options: Parameters<typeof aws.config.update>[0];
constructor(protected queueUrl: string, options: ServiceConfigurationOptions) {
this.options = options;
this.sqs = new SQS({ ...options, apiVersion: '2012-11-05' });
}
protected async publishToSqs(body: Record<string, unknown>) {
await this.sqs
.sendMessage({
QueueUrl: this.queueUrl,
MessageBody: JSON.stringify(body),
})
.promise();
}
}
Unable to find out why this issue is happening? For normal body like {notificationId: 2345} works well but sometimes it throws error shown above.

How to return HTML from Next.js middleware?

I'm trying to return HTTP Status Code 410 (gone) alongside a custom simple HTML:
<h1>Error 410</h1>
<h2>Permanently deleted or Gone</h2>
<p>This page is not found and is gone from this server forever</p>
Is it possible? Because I can't find a method on NextResponse object.
How can I return HTML from middleware?
This is not supported anymore.
Middleware can no longer produce a response body as of v12.2+.
https://nextjs.org/docs/messages/returning-response-body-in-middleware
this is the type. there is no method to send html
type NextApiResponse<T = any> = ServerResponse<IncomingMessage> & {
send: Send<T>;
json: Send<T>;
status: (statusCode: number) => NextApiResponse<T>;
redirect(url: string): NextApiResponse<T>;
redirect(status: number, url: string): NextApiResponse<T>;
setPreviewData: (data: object | string, options?: {
maxAge?: number;
path?: string;
}) => NextApiResponse<T>;
clearPreviewData: (options?: {
path?: string;
}) => NextApiResponse<T>;
unstable_revalidate: () => void;
revalidate: (urlPath: string, opts?: {
unstable_onlyGenerated?: boolean;
}) => Promise<void>;
}
express has sendFile
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
NextApiResponse, sendandjson`
res.json(body) - Sends a JSON response. body must be a serializable object
res.send(body) - Sends the HTTP response. body can be a string, an object or a Buffer
you can redirect the user to a URL where you display your html
While it's true that returning a response body from middleware has been disabled from version v12.2, Next.js v13 reintroduced the ability to produce a response as an experimental feature through the allowMiddlewareResponseBody flag in next.config.js.
// next.config.js
module.exports = {
experimental: {
allowMiddlewareResponseBody: true
}
}
After enabling this experimental flag, you can return a response from your middleware as follows.
import { NextResponse } from 'next/server'
export function middleware(request) {
return new NextResponse(
`
<h1>Error 410</h1>
<h2>Permanently deleted or Gone</h2>
<p>This page is not found and is gone from this server forever</p>
`,
{ status: 410, headers: { 'content-type': 'text/html' } }
)
}

Looking for a way to destructure object and pass optional arguments to another method if they are exist

I want to make some properties optional and check whether propery exists and if it is I want to give it to this.UserService.update() method. I mean that i'm trying to update only those values which are passed to req.body.
user.controller.ts
private updateUser = async (
req: Request,
res: Response,
next: NextFunction
): Promise<Response | void> => {
try {
const id = req.user.id;
//I want to check every value below exist whether it exists
const { old_password, name, email, password } = req.body;
// Some of they may be empty and if some of them are not I want to give
// them to the method below
const updatedUser = await this.UserService.update(id, /* here */);
return res.status(200).json({ updatedUser });
} catch (error: any) {
next(new HttpException(400, error.message));
}
};
user.service.ts
public async update(
id: string,
old_password: string,
name?: string,
password?: string,
email?: string
){}
You can directly check in update function:
public async update(
id: string,
old_password: string,
name?: string,
password?: string,
email?: string
){
if(name) {
// Update name
}
if(email) {
// Update email
}
// ....
}

Express TypeScript: Why is my controller method throwing error message?

folks. I'm just getting started with TypeScript and, thus, part of getting my feet wet includes converting a Express backend I built to TS. All has been well to this point, but now I got some rather unusual issues. Specifically, the lines const hasVoted = poll.votedBy.some((voter): boolean => voter.equals(voterId)); and const choice = await poll.choices.id(choiceId); in the code snippet below, which result in Property 'equals' does not exist on type 'string' and Property 'choices' does not exist on type 'Poll & Document' error messages respectively. For reference, I has the JS version working just fine, so what is it that I may be missing here?
Post Controller
import * as mongoose from 'mongoose';
import { Request, Response } from 'express';
import { Poll } from '../models/index';
class PollsController {
public async addNewPoll(req: Request, res: Response) {
// ...
}
public async voteInPoll(req: Request, res: Response) {
const { category, pollId } = req.params;
const { name, choiceId, voterId } = req.body;
try {
const poll = await Poll.findById(pollId);
// Check if user has already voted in poll
const hasVoted = poll.votedBy.some((voter): boolean => voter.equals(voterId));
if (!voterId) {
res
.status(401)
.json({ message: 'Sorry, you must be logged in to vote' });
} else if (voterId && hasVoted) {
res
.status(401)
.json({ message: 'Sorry, you have already participated in poll' });
} else {
const choice = await poll.choices.id(choiceId);
const votedChoice = { name, votes: choice.votes + 1 };
await choice.set(votedChoice);
await poll.votedBy.push(voterId);
poll.save();
res
.status(200)
.json({
message: 'Thank you for voting.',
poll,
});
}
} catch (error) {
res.status(404).json({ error });
}
}
// ...
}
export default PollsController
Poll Interface
interface Poll {
title: string;
category: string;
addedBy: string;
votedBy?: [string];
}
export default Poll;
Poll Schema
import * as mongoose from 'mongoose';
import PollInterface from './poll.interface';
const Schema = mongoose.Schema;
const ChoiceSchema = new Schema({
name: { type: String },
votes: { type: Number }
});
const PollSchema = new Schema({
title: { type: String },
category: { type: String },
choices: [ChoiceSchema],
addedBy: { type: Schema.Types.ObjectId, ref: 'User' },
votedBy: [{ type: Schema.Types.ObjectId, ref: 'User' }]
},{
timestamps: true,
});
const Poll = mongoose.model<PollInterface & mongoose.Document>('Poll', PollSchema);
export default Poll;
Edit: Included both Poll interface and schema code snippets
For the first error, your interface defines votedBy as an array of strings. You can call .some on an array but then you are calling .equals on a string which is not a method on type string. You can change
const hasVoted = poll.votedBy.some((voter): boolean => voter.equals(voterId));
to
const hasVoted = poll.votedBy.some((voter): boolean => voter === voterId);
And the second one, you do not define choices on your Poll interface. So the following line fails the typescript compiler because of it.
const choice = await poll.choices.id(choiceId);
You need to add choices as property on your Poll interface. I don't know exactly what your implementation is but you would want to add something like the following to your Poll interface.
choices: {
id:() => string;
}
From your code, it looks like you are trying to find a matching choice from a given choiceId.
Property 'equals' does not exist on type 'string': if it works in JS, it mean voter is not a 'string' as you declared.
Check the signature of your method Poll.findById(pollId).

TypeScript type annotation for res.body

I'm using typescript for my app node.js express.
I would like say the res.body is type personne.
I have tried this:
router.post('/',(req: Request, res: Response) => {
const defunt:PersoneModel = res.(<PersoneModel>body);
}
I have this model:
export type PersoneModel = mongoose.Document & {
nom: String,
prenom: String,
}
Can you help me?
Thank you.
Update:
As of #types/express#4.17.2, the Request type uses generics.
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/express/index.d.ts#L107
interface Request<P extends core.Params = core.ParamsDictionary, ResBody = any, ReqBody = any, ReqQuery = core.Query> extends core.Request<P, ResBody, ReqBody, ReqQuery> { }
You could set the type of req.body to PersoneModel like this:
import { Request, Response } from 'express';
router.post('/',(req: Request<{}, {}, PersoneModel>, res: Response) => {
// req.body is now PersoneModel
}
For #types/express#4.17.1 and below
Encountered similar problem and I solved it using generics:
import { Request, Response } from 'express';
interface PersoneModel extends mongoose.Document {
nom: String,
prenom: String,
}
interface CustomRequest<T> extends Request {
body: T
}
router.post('/',(req: CustomRequest<PersoneModel>, res: Response) => {
// req.body is now PersoneModel
}
We can use as. This should be enough to imply that res.body is PersoneModel
const defunt = res.body as PersoneModel;
However more straightforward way is declaring type of the variable as a PersoneModel
const defunt: PersoneModel = res.body;
router.post('/',(req: Omit<Request,'body'> & { body: PersoneModel }, res: Response) => {
// code
}
this also will do, useful if you want to create abstration
Here is what worked for me (I am using node, express, and a postgres Pool connection):
import express, { Response, Request } from 'express';
export interface ITeamsRequest {
teams?: ITeam[];
divisions?: ITournamentDivision[];
}
export function setupTeams(app: express.Application, client: Pool) {
app.get(
'/teams',
async (req: Request, res: Response<ITeamsRequest>) => {
const teams = // get teams;
const divisions = // get divisions;
res.status(200);
return res.json({ teams, divisions });
},
);
}
The key thing is to manually import Request and Response, and using a type generic (Response<ITeamsRequest>) you can define your own ResBody type.
This was on express version 4.17.1 and #types/express 4.17.11

Categories