What should I use as validation tool using NestJS and MongoDB? - mongodb

Let's say, I am creating application using NestJS. I use MongoDB as a database and mongoose as ODM. So, NestJS has it's own way to validate data - ValidationPipe's. On the other side, there is mongoose built-in ways to validate data that being pushed into DB.
The question is - can I use only NestJS validation or do I need also second-check my data using mongoose validation tools?
Personally, I can't see why should I use additional layer of validation if I already have NestJS validation. But maybe there is best-practice or something?

Each database validates input data and emits an error if found. However, you must take into account your schema file. For instance, if you are using Prisma(It doesn't actually matter) and you have a User model like below
model User {
id String #id #default(auto()) #map("_id") #db.ObjectId
email String #unique
password String
name String
image String?
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
##map("user")
}
As you can see there is only one optional property "image". Whether you pass a value for image property or not, the database will insert the data as a row. On the other hand, the properties without "?" mark at the end of the type, will not be stored if you don't pass them and emit an error.
Therefore, if you modeled schema according to your business logic, you don't need to validate twice but only add an exception handling like the one below.
const user = await this.usersService.findOne('id...')
.catch((e) => new NotFoundException({ message: 'No user found.' }))

Related

Is there a way to create public/private fields for a mongodb schema in golang?

I'm creating a backend for a moderately large-scale application, and I came across a difficulty with restraining what fields users can access. For instance, a user should not be able to modify their follower count with a PUT request to an update endpoint, yet the only way to really remove the followerCount field from the golang struct representing the user schema is by creating an entirely new schema for updates in particular. I've been doing this, and my backend code base is way more complex than it needs to be, to the point where it's nearly unmanageable.
Here's an example of the schemas I have:
type User struct {
ID primitive.ObjectID `bson:"_id" json:"_id"`
// CHANGEABLE
Username string `bson:"username" json:"username"`
Email string `bson:"email" json:"email"`
Password string `bson:"password" json:"password"`
Archived bool `bson:"archived" json:"archived"`
// UNCHANGEABLE
Sessions []primitive.ObjectID `bson:"sessions" json:"sessions"`
IsCreator bool `bson:"isCreator" json:"isCreator"`
FollowerCount int `bson:"followerCount" json:"followerCount"`
}
and for updates specifically
type UserUpdate struct {
Username string `bson:"username,omitempty" json:"username,omitempty"`
Email string `bson:"email,omitempty" json:"email,omitempty"`
Password string `bson:"password,omitempty" json:"password,omitempty"`
Archived bool `bson:"archived,omitempty" json:"archived,omitempty"`
}
Is there a way to make public/private fields within a mongo schema so I can simplify this process? And if not, can you advise me on a better solution? Nothing is coming to mind for me.
I've continued creating new "sub-schemas" built off the same schema for specific purposes (i.e. Creation, Updating, Getting, etc.). Changing one field name takes nearly 30 minutes to change across schemas, which is not ideal.

Use a field's generated value as another field's default value in prisma?

I have this User model in prisma (postgres), I want to use the same value cuid() generates for id in username. How do I achieve that?
model User {
id String #id #default(cuid())
username String? #unique
}
I know I can just regenerate cuid() for a different value, it would still work for what I am working on, but I want user's id and username to be same by default.

.net core handle PostreSQL db exceptions

I have a .net core web api. Db is PostreSQL. I have a simple POST request that create an entity with two fields:
public class ClientDto{
public string Name {get;set;}
public int ClientId{get;set;}
}
ClientId - FK foreign key to table Clients.
Some client (Postman for exapmle) execute request, but in data model send ClientId that not exists in db.
I have global exeption handler and there I handle db exception, but exception object don't include separated information.
I would like to show to user beautiful message something like "Client with id = 1 not exists".
What the best practis to handle db exceptions?
May be before save object in db I need check if client with id = 1 exists in db? But it is an additional query.
May be before save object in db I need check if client with id = 1 exists in db? But it is an additional query.
I'd do this.
If your client doesn't give you good information in its exception then your probably better to do the additional query. If you're querying on an indexed field (which i'd expect given you are using a foreign key) then it will be a very quick query.
Exception throwing and catching is fairly expensive anyway and i'd probably be happy enough with the extra call.

Postgres NestJS Prisma migration - Database error code: 23502 column of relation contains null values

I updated my Prisma ORM database model by adding two more fields 'ahash' and 'sAddress' to the 'invitation' table.
The table already contains 6 rows of data.
When I try to migrate the new changes to the Postgresql database, I get the error Database error code: 23502. ERROR: column "aHash" of relation "Invitation" contains null values.
How do I cater for the null values and migrate the model updates smoothly onto the database?
Give me a Step by step account please. I'm new to Prisma migration.
Thanks in advance!
The Prisma invitation model looks like below.
model Invitation {
id String #id #db.Uuid
workId String #db.Uuid
work Work #relation(fields: [workId], references: [id])
status RequestStatus
coId String #db.Uuid
oSignature String
note String
aHash String
sAddress String
createdAt DateTime
respondedAt DateTime
}
The problem here is that ahash and sAddress are both mandatory fields. However, they do not exist for the 6 existing rows/records in your database.
If you want to add new columns to an existing database without causing data loss you need to make sure the new columns/field are optional. This can be done in Prisma by marking the type of the field with a ?.
If you need the field to be mandatory, you could do it in three steps:
Create the new ahash and sAddress fields as optional first in your prisma schema and run a migration.
Run a script to update all existing records, so that they have a value for the ahash and sAddress fields.
Mark both fields as mandatory in your Prisma schema and run a migration.
In step 3, you will no longer get the error because none of the records contain a null value for the ahash and sAddress fields.

Is it possible to access metadata about the prisma model?

Let's say I have a model in my schema.prisma file:
model Post {
id Int #id #default(autoincrement())
author User #relation(fields: [authorId], references: [id])
authorId Int
}
Having a variable called model in my server containing a model name
const model: string = [model name generated dynamically]
Using this string I want to know every information about this model. For example if this variable model happens to be Post, I want to know that it has fields id, author, authorId and also information about each field separately, like in the case of author which field in which model does it reference, in this example the model User the field id.
I'm aware that prisma generates a type for each model and that way maybe I can access the fields that way but that't not enough for me, I want information about each fields as well.
I search the prisma docs, also googled something like 'get meta information about model in prisma2' but I didn't find any solution. Is there a way to achieve this?
Yes, you can get all the metadata for your entire schema in the following manner:
const prisma = new PrismaClient()
// #ts-ignore
console.log(prisma._dmmf)
This will give you all the details for the models and relations. The reason this is not documented is that this is highly experimental and will change with releases, which is why it's used for internal purposes only.